blob: c662a2b9964ea3eba8b6872a4632546fe6528576 [file] [log] [blame]
Sagar Dharia33beca02012-10-22 16:21:46 -06001/* Copyright (c) 2011-2013, 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#include <linux/irq.h>
13#include <linux/kernel.h>
14#include <linux/init.h>
15#include <linux/slab.h>
16#include <linux/io.h>
17#include <linux/interrupt.h>
18#include <linux/platform_device.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070019#include <linux/slimbus/slimbus.h>
20#include <linux/delay.h>
21#include <linux/kthread.h>
22#include <linux/clk.h>
Sagar Dharia45ee38a2011-08-03 17:01:31 -060023#include <linux/pm_runtime.h>
Sagar Dhariaf8f603b2012-03-21 15:25:17 -060024#include <linux/of.h>
25#include <linux/of_slimbus.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070026#include <mach/sps.h>
Joonwoo Parkf69f77a2012-08-28 15:26:11 -070027#include <mach/qdsp6v2/apr.h>
Sagar Dharia2754ab42012-08-21 18:07:39 -060028#include "slim-msm.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070029
30#define MSM_SLIM_NAME "msm_slim_ctrl"
31#define SLIM_ROOT_FREQ 24576000
32
Sagar Dharia45ee38a2011-08-03 17:01:31 -060033#define QC_MSM_DEVS 5
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070034
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070035/* Manager registers */
36enum mgr_reg {
37 MGR_CFG = 0x200,
38 MGR_STATUS = 0x204,
39 MGR_RX_MSGQ_CFG = 0x208,
40 MGR_INT_EN = 0x210,
41 MGR_INT_STAT = 0x214,
42 MGR_INT_CLR = 0x218,
43 MGR_TX_MSG = 0x230,
44 MGR_RX_MSG = 0x270,
Sagar Dhariaac913452012-09-04 11:27:26 -060045 MGR_IE_STAT = 0x2F0,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070046 MGR_VE_STAT = 0x300,
47};
48
49enum msg_cfg {
50 MGR_CFG_ENABLE = 1,
51 MGR_CFG_RX_MSGQ_EN = 1 << 1,
52 MGR_CFG_TX_MSGQ_EN_HIGH = 1 << 2,
53 MGR_CFG_TX_MSGQ_EN_LOW = 1 << 3,
54};
55/* Message queue types */
56enum msm_slim_msgq_type {
57 MSGQ_RX = 0,
58 MSGQ_TX_LOW = 1,
59 MSGQ_TX_HIGH = 2,
60};
61/* Framer registers */
62enum frm_reg {
63 FRM_CFG = 0x400,
64 FRM_STAT = 0x404,
65 FRM_INT_EN = 0x410,
66 FRM_INT_STAT = 0x414,
67 FRM_INT_CLR = 0x418,
68 FRM_WAKEUP = 0x41C,
69 FRM_CLKCTL_DONE = 0x420,
70 FRM_IE_STAT = 0x430,
71 FRM_VE_STAT = 0x440,
72};
73
74/* Interface registers */
75enum intf_reg {
76 INTF_CFG = 0x600,
77 INTF_STAT = 0x604,
78 INTF_INT_EN = 0x610,
79 INTF_INT_STAT = 0x614,
80 INTF_INT_CLR = 0x618,
81 INTF_IE_STAT = 0x630,
82 INTF_VE_STAT = 0x640,
83};
84
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070085enum mgr_intr {
86 MGR_INT_RECFG_DONE = 1 << 24,
87 MGR_INT_TX_NACKED_2 = 1 << 25,
88 MGR_INT_MSG_BUF_CONTE = 1 << 26,
89 MGR_INT_RX_MSG_RCVD = 1 << 30,
90 MGR_INT_TX_MSG_SENT = 1 << 31,
91};
92
93enum frm_cfg {
94 FRM_ACTIVE = 1,
95 CLK_GEAR = 7,
96 ROOT_FREQ = 11,
97 REF_CLK_GEAR = 15,
Sagar Dhariadebc8b72012-08-11 15:02:12 -060098 INTR_WAKE = 19,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070099};
100
Sagar Dharia790cfd02011-09-25 17:56:24 -0600101static struct msm_slim_sat *msm_slim_alloc_sat(struct msm_slim_ctrl *dev);
102
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700103static int msm_sat_enqueue(struct msm_slim_sat *sat, u32 *buf, u8 len)
104{
105 struct msm_slim_ctrl *dev = sat->dev;
Stephen Boyd3cdfc712012-10-31 17:41:43 -0700106 unsigned long flags;
107 spin_lock_irqsave(&sat->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700108 if ((sat->stail + 1) % SAT_CONCUR_MSG == sat->shead) {
Stephen Boyd3cdfc712012-10-31 17:41:43 -0700109 spin_unlock_irqrestore(&sat->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700110 dev_err(dev->dev, "SAT QUEUE full!");
111 return -EXFULL;
112 }
113 memcpy(sat->sat_msgs[sat->stail], (u8 *)buf, len);
114 sat->stail = (sat->stail + 1) % SAT_CONCUR_MSG;
Stephen Boyd3cdfc712012-10-31 17:41:43 -0700115 spin_unlock_irqrestore(&sat->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700116 return 0;
117}
118
119static int msm_sat_dequeue(struct msm_slim_sat *sat, u8 *buf)
120{
121 unsigned long flags;
122 spin_lock_irqsave(&sat->lock, flags);
123 if (sat->stail == sat->shead) {
124 spin_unlock_irqrestore(&sat->lock, flags);
125 return -ENODATA;
126 }
127 memcpy(buf, sat->sat_msgs[sat->shead], 40);
128 sat->shead = (sat->shead + 1) % SAT_CONCUR_MSG;
129 spin_unlock_irqrestore(&sat->lock, flags);
130 return 0;
131}
132
133static void msm_get_eaddr(u8 *e_addr, u32 *buffer)
134{
135 e_addr[0] = (buffer[1] >> 24) & 0xff;
136 e_addr[1] = (buffer[1] >> 16) & 0xff;
137 e_addr[2] = (buffer[1] >> 8) & 0xff;
138 e_addr[3] = buffer[1] & 0xff;
139 e_addr[4] = (buffer[0] >> 24) & 0xff;
140 e_addr[5] = (buffer[0] >> 16) & 0xff;
141}
142
143static bool msm_is_sat_dev(u8 *e_addr)
144{
145 if (e_addr[5] == QC_MFGID_LSB && e_addr[4] == QC_MFGID_MSB &&
146 e_addr[2] != QC_CHIPID_SL &&
147 (e_addr[1] == QC_DEVID_SAT1 || e_addr[1] == QC_DEVID_SAT2))
148 return true;
149 return false;
150}
151
Sagar Dharia790cfd02011-09-25 17:56:24 -0600152static struct msm_slim_sat *addr_to_sat(struct msm_slim_ctrl *dev, u8 laddr)
153{
154 struct msm_slim_sat *sat = NULL;
155 int i = 0;
156 while (!sat && i < dev->nsats) {
157 if (laddr == dev->satd[i]->satcl.laddr)
158 sat = dev->satd[i];
159 i++;
160 }
161 return sat;
162}
163
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700164static irqreturn_t msm_slim_interrupt(int irq, void *d)
165{
166 struct msm_slim_ctrl *dev = d;
167 u32 pstat;
168 u32 stat = readl_relaxed(dev->base + MGR_INT_STAT);
169
170 if (stat & MGR_INT_TX_MSG_SENT || stat & MGR_INT_TX_NACKED_2) {
171 if (stat & MGR_INT_TX_MSG_SENT)
172 writel_relaxed(MGR_INT_TX_MSG_SENT,
173 dev->base + MGR_INT_CLR);
174 else {
Sagar Dhariaac913452012-09-04 11:27:26 -0600175 u32 mgr_stat = readl_relaxed(dev->base + MGR_STATUS);
176 u32 mgr_ie_stat = readl_relaxed(dev->base +
177 MGR_IE_STAT);
178 u32 frm_stat = readl_relaxed(dev->base + FRM_STAT);
179 u32 frm_cfg = readl_relaxed(dev->base + FRM_CFG);
180 u32 frm_intr_stat = readl_relaxed(dev->base +
181 FRM_INT_STAT);
182 u32 frm_ie_stat = readl_relaxed(dev->base +
183 FRM_IE_STAT);
184 u32 intf_stat = readl_relaxed(dev->base + INTF_STAT);
185 u32 intf_intr_stat = readl_relaxed(dev->base +
186 INTF_INT_STAT);
187 u32 intf_ie_stat = readl_relaxed(dev->base +
188 INTF_IE_STAT);
189
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700190 writel_relaxed(MGR_INT_TX_NACKED_2,
191 dev->base + MGR_INT_CLR);
Sagar Dhariaac913452012-09-04 11:27:26 -0600192 pr_err("TX Nack MGR dump:int_stat:0x%x, mgr_stat:0x%x",
193 stat, mgr_stat);
194 pr_err("TX Nack MGR dump:ie_stat:0x%x", mgr_ie_stat);
195 pr_err("TX Nack FRM dump:int_stat:0x%x, frm_stat:0x%x",
196 frm_intr_stat, frm_stat);
197 pr_err("TX Nack FRM dump:frm_cfg:0x%x, ie_stat:0x%x",
198 frm_cfg, frm_ie_stat);
199 pr_err("TX Nack INTF dump:intr_st:0x%x, intf_stat:0x%x",
200 intf_intr_stat, intf_stat);
201 pr_err("TX Nack INTF dump:ie_stat:0x%x", intf_ie_stat);
202
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700203 dev->err = -EIO;
204 }
205 /*
206 * Guarantee that interrupt clear bit write goes through before
207 * signalling completion/exiting ISR
208 */
209 mb();
210 if (dev->wr_comp)
211 complete(dev->wr_comp);
212 }
213 if (stat & MGR_INT_RX_MSG_RCVD) {
214 u32 rx_buf[10];
215 u32 mc, mt;
216 u8 len, i;
217 rx_buf[0] = readl_relaxed(dev->base + MGR_RX_MSG);
218 len = rx_buf[0] & 0x1F;
219 for (i = 1; i < ((len + 3) >> 2); i++) {
220 rx_buf[i] = readl_relaxed(dev->base + MGR_RX_MSG +
221 (4 * i));
222 dev_dbg(dev->dev, "reading data: %x\n", rx_buf[i]);
223 }
224 mt = (rx_buf[0] >> 5) & 0x7;
225 mc = (rx_buf[0] >> 8) & 0xff;
226 dev_dbg(dev->dev, "MC: %x, MT: %x\n", mc, mt);
227 if (mt == SLIM_MSG_MT_DEST_REFERRED_USER ||
228 mt == SLIM_MSG_MT_SRC_REFERRED_USER) {
Sagar Dharia790cfd02011-09-25 17:56:24 -0600229 u8 laddr = (u8)((rx_buf[0] >> 16) & 0xFF);
230 struct msm_slim_sat *sat = addr_to_sat(dev, laddr);
231 if (sat)
232 msm_sat_enqueue(sat, rx_buf, len);
233 else
234 dev_err(dev->dev, "unknown sat:%d message",
235 laddr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700236 writel_relaxed(MGR_INT_RX_MSG_RCVD,
237 dev->base + MGR_INT_CLR);
238 /*
239 * Guarantee that CLR bit write goes through before
240 * queuing work
241 */
242 mb();
Sagar Dharia790cfd02011-09-25 17:56:24 -0600243 if (sat)
244 queue_work(sat->wq, &sat->wd);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700245 } else if (mt == SLIM_MSG_MT_CORE &&
246 mc == SLIM_MSG_MC_REPORT_PRESENT) {
247 u8 e_addr[6];
248 msm_get_eaddr(e_addr, rx_buf);
Sagar Dharia790cfd02011-09-25 17:56:24 -0600249 msm_slim_rx_enqueue(dev, rx_buf, len);
250 writel_relaxed(MGR_INT_RX_MSG_RCVD, dev->base +
251 MGR_INT_CLR);
252 /*
253 * Guarantee that CLR bit write goes through
254 * before signalling completion
255 */
256 mb();
257 complete(&dev->rx_msgq_notify);
Kiran Gunda33a23a92013-01-10 17:03:33 +0530258 } else if (mt == SLIM_MSG_MT_CORE &&
259 mc == SLIM_MSG_MC_REPORT_ABSENT) {
260 writel_relaxed(MGR_INT_RX_MSG_RCVD, dev->base +
261 MGR_INT_CLR);
262 /*
263 * Guarantee that CLR bit write goes through
264 * before signalling completion
265 */
266 mb();
267 complete(&dev->rx_msgq_notify);
268
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700269 } else if (mc == SLIM_MSG_MC_REPLY_INFORMATION ||
270 mc == SLIM_MSG_MC_REPLY_VALUE) {
271 msm_slim_rx_enqueue(dev, rx_buf, len);
272 writel_relaxed(MGR_INT_RX_MSG_RCVD, dev->base +
273 MGR_INT_CLR);
274 /*
275 * Guarantee that CLR bit write goes through
276 * before signalling completion
277 */
278 mb();
279 complete(&dev->rx_msgq_notify);
Sagar Dharia144e5e02011-08-08 17:30:11 -0600280 } else if (mc == SLIM_MSG_MC_REPORT_INFORMATION) {
281 u8 *buf = (u8 *)rx_buf;
282 u8 l_addr = buf[2];
283 u16 ele = (u16)buf[4] << 4;
284 ele |= ((buf[3] & 0xf0) >> 4);
285 dev_err(dev->dev, "Slim-dev:%d report inf element:0x%x",
286 l_addr, ele);
287 for (i = 0; i < len - 5; i++)
288 dev_err(dev->dev, "offset:0x%x:bit mask:%x",
289 i, buf[i+5]);
290 writel_relaxed(MGR_INT_RX_MSG_RCVD, dev->base +
291 MGR_INT_CLR);
292 /*
293 * Guarantee that CLR bit write goes through
294 * before exiting
295 */
296 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700297 } else {
298 dev_err(dev->dev, "Unexpected MC,%x MT:%x, len:%d",
299 mc, mt, len);
300 for (i = 0; i < ((len + 3) >> 2); i++)
301 dev_err(dev->dev, "error msg: %x", rx_buf[i]);
302 writel_relaxed(MGR_INT_RX_MSG_RCVD, dev->base +
303 MGR_INT_CLR);
304 /*
305 * Guarantee that CLR bit write goes through
306 * before exiting
307 */
308 mb();
309 }
310 }
311 if (stat & MGR_INT_RECFG_DONE) {
312 writel_relaxed(MGR_INT_RECFG_DONE, dev->base + MGR_INT_CLR);
313 /*
314 * Guarantee that CLR bit write goes through
315 * before exiting ISR
316 */
317 mb();
318 complete(&dev->reconf);
319 }
Sagar Dharia82e516f2012-03-16 16:01:23 -0600320 pstat = readl_relaxed(PGD_THIS_EE(PGD_PORT_INT_ST_EEn, dev->ver));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700321 if (pstat != 0) {
Sagar Dharia2b8a4b52013-05-15 20:01:45 -0600322 return msm_slim_port_irq_handler(dev, pstat);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700323 }
324
325 return IRQ_HANDLED;
326}
327
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700328static int msm_xfer_msg(struct slim_controller *ctrl, struct slim_msg_txn *txn)
329{
330 DECLARE_COMPLETION_ONSTACK(done);
331 struct msm_slim_ctrl *dev = slim_get_ctrldata(ctrl);
332 u32 *pbuf;
333 u8 *puc;
334 int timeout;
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700335 int msgv = -1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700336 u8 la = txn->la;
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600337 u8 mc = (u8)(txn->mc & 0xFF);
338 /*
339 * Voting for runtime PM: Slimbus has 2 possible use cases:
340 * 1. messaging
341 * 2. Data channels
342 * Messaging case goes through messaging slots and data channels
343 * use their own slots
344 * This "get" votes for messaging bandwidth
345 */
346 if (!(txn->mc & SLIM_MSG_CLK_PAUSE_SEQ_FLG))
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700347 msgv = msm_slim_get_ctrl(dev);
Sagar Dhariad1468b72013-07-16 12:56:22 -0600348 if (msgv >= 0)
349 dev->state = MSM_CTRL_AWAKE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700350 mutex_lock(&dev->tx_lock);
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700351 if (dev->state == MSM_CTRL_ASLEEP ||
352 ((!(txn->mc & SLIM_MSG_CLK_PAUSE_SEQ_FLG)) &&
Sagar Dhariad1468b72013-07-16 12:56:22 -0600353 dev->state == MSM_CTRL_IDLE)) {
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600354 dev_err(dev->dev, "runtime or system PM suspended state");
355 mutex_unlock(&dev->tx_lock);
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700356 if (msgv >= 0)
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600357 msm_slim_put_ctrl(dev);
358 return -EBUSY;
359 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700360 if (txn->mt == SLIM_MSG_MT_CORE &&
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600361 mc == SLIM_MSG_MC_BEGIN_RECONFIGURATION) {
362 if (dev->reconf_busy) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700363 wait_for_completion(&dev->reconf);
364 dev->reconf_busy = false;
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600365 }
366 /* This "get" votes for data channels */
367 if (dev->ctrl.sched.usedslots != 0 &&
368 !dev->chan_active) {
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700369 int chv = msm_slim_get_ctrl(dev);
370 if (chv >= 0)
371 dev->chan_active = true;
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600372 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700373 }
374 txn->rl--;
Sagar Dharia2754ab42012-08-21 18:07:39 -0600375 pbuf = msm_get_msg_buf(dev, txn->rl);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700376 dev->wr_comp = NULL;
377 dev->err = 0;
378
379 if (txn->dt == SLIM_MSG_DEST_ENUMADDR) {
380 mutex_unlock(&dev->tx_lock);
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700381 if (msgv >= 0)
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600382 msm_slim_put_ctrl(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700383 return -EPROTONOSUPPORT;
384 }
385 if (txn->mt == SLIM_MSG_MT_CORE && txn->la == 0xFF &&
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600386 (mc == SLIM_MSG_MC_CONNECT_SOURCE ||
387 mc == SLIM_MSG_MC_CONNECT_SINK ||
388 mc == SLIM_MSG_MC_DISCONNECT_PORT))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700389 la = dev->pgdla;
390 if (txn->dt == SLIM_MSG_DEST_LOGICALADDR)
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600391 *pbuf = SLIM_MSG_ASM_FIRST_WORD(txn->rl, txn->mt, mc, 0, la);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700392 else
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600393 *pbuf = SLIM_MSG_ASM_FIRST_WORD(txn->rl, txn->mt, mc, 1, la);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700394 if (txn->dt == SLIM_MSG_DEST_LOGICALADDR)
395 puc = ((u8 *)pbuf) + 3;
396 else
397 puc = ((u8 *)pbuf) + 2;
398 if (txn->rbuf)
399 *(puc++) = txn->tid;
400 if ((txn->mt == SLIM_MSG_MT_CORE) &&
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600401 ((mc >= SLIM_MSG_MC_REQUEST_INFORMATION &&
402 mc <= SLIM_MSG_MC_REPORT_INFORMATION) ||
403 (mc >= SLIM_MSG_MC_REQUEST_VALUE &&
404 mc <= SLIM_MSG_MC_CHANGE_VALUE))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700405 *(puc++) = (txn->ec & 0xFF);
406 *(puc++) = (txn->ec >> 8)&0xFF;
407 }
408 if (txn->wbuf)
409 memcpy(puc, txn->wbuf, txn->len);
410 if (txn->mt == SLIM_MSG_MT_CORE && txn->la == 0xFF &&
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600411 (mc == SLIM_MSG_MC_CONNECT_SOURCE ||
412 mc == SLIM_MSG_MC_CONNECT_SINK ||
413 mc == SLIM_MSG_MC_DISCONNECT_PORT)) {
414 if (mc != SLIM_MSG_MC_DISCONNECT_PORT)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700415 dev->err = msm_slim_connect_pipe_port(dev, *puc);
416 else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700417 /*
418 * Remove channel disconnects master-side ports from
419 * channel. No need to send that again on the bus
Sagar Dharia2d74c142013-05-17 02:24:06 -0600420 * Only disable port
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700421 */
Sagar Dharia2d74c142013-05-17 02:24:06 -0600422 writel_relaxed(0, PGD_PORT(PGD_PORT_CFGn,
423 (*puc + dev->port_b), dev->ver));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700424 mutex_unlock(&dev->tx_lock);
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700425 if (msgv >= 0)
426 msm_slim_put_ctrl(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700427 return 0;
428 }
429 if (dev->err) {
430 dev_err(dev->dev, "pipe-port connect err:%d", dev->err);
431 mutex_unlock(&dev->tx_lock);
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700432 if (msgv >= 0)
433 msm_slim_put_ctrl(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700434 return dev->err;
435 }
Sagar Dharia2b8a4b52013-05-15 20:01:45 -0600436 *(puc) = *(puc) + dev->port_b;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700437 }
438 if (txn->mt == SLIM_MSG_MT_CORE &&
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600439 mc == SLIM_MSG_MC_BEGIN_RECONFIGURATION)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700440 dev->reconf_busy = true;
441 dev->wr_comp = &done;
Sagar Dharia2754ab42012-08-21 18:07:39 -0600442 msm_send_msg_buf(dev, pbuf, txn->rl, MGR_TX_MSG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700443 timeout = wait_for_completion_timeout(&done, HZ);
Sagar Dhariaac913452012-09-04 11:27:26 -0600444 if (!timeout)
445 dev->wr_comp = NULL;
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700446 if (mc == SLIM_MSG_MC_RECONFIGURE_NOW) {
447 if ((txn->mc == (SLIM_MSG_MC_RECONFIGURE_NOW |
448 SLIM_MSG_CLK_PAUSE_SEQ_FLG)) &&
449 timeout) {
450 timeout = wait_for_completion_timeout(&dev->reconf, HZ);
451 dev->reconf_busy = false;
452 if (timeout) {
Sagar Dharia9acf7f42012-03-08 09:45:30 -0700453 clk_disable_unprepare(dev->rclk);
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700454 disable_irq(dev->irq);
455 }
456 }
457 if ((txn->mc == (SLIM_MSG_MC_RECONFIGURE_NOW |
458 SLIM_MSG_CLK_PAUSE_SEQ_FLG)) &&
459 !timeout) {
460 dev->reconf_busy = false;
461 dev_err(dev->dev, "clock pause failed");
462 mutex_unlock(&dev->tx_lock);
463 return -ETIMEDOUT;
464 }
465 if (txn->mt == SLIM_MSG_MT_CORE &&
466 txn->mc == SLIM_MSG_MC_RECONFIGURE_NOW) {
467 if (dev->ctrl.sched.usedslots == 0 &&
468 dev->chan_active) {
469 dev->chan_active = false;
470 msm_slim_put_ctrl(dev);
471 }
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600472 }
473 }
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600474 mutex_unlock(&dev->tx_lock);
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700475 if (msgv >= 0)
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600476 msm_slim_put_ctrl(dev);
477
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700478 if (!timeout)
479 dev_err(dev->dev, "TX timed out:MC:0x%x,mt:0x%x", txn->mc,
480 txn->mt);
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600481
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700482 return timeout ? dev->err : -ETIMEDOUT;
483}
484
Sagar Dhariaac913452012-09-04 11:27:26 -0600485static void msm_slim_wait_retry(struct msm_slim_ctrl *dev)
486{
487 int msec_per_frm = 0;
488 int sfr_per_sec;
489 /* Wait for 1 superframe, or default time and then retry */
490 sfr_per_sec = dev->framer.superfreq /
491 (1 << (SLIM_MAX_CLK_GEAR - dev->ctrl.clkgear));
492 if (sfr_per_sec)
493 msec_per_frm = MSEC_PER_SEC / sfr_per_sec;
494 if (msec_per_frm < DEF_RETRY_MS)
495 msec_per_frm = DEF_RETRY_MS;
496 msleep(msec_per_frm);
497}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700498static int msm_set_laddr(struct slim_controller *ctrl, const u8 *ea,
499 u8 elen, u8 laddr)
500{
501 struct msm_slim_ctrl *dev = slim_get_ctrldata(ctrl);
Sagar Dhariaac913452012-09-04 11:27:26 -0600502 struct completion done;
503 int timeout, ret, retries = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700504 u32 *buf;
Sagar Dhariaac913452012-09-04 11:27:26 -0600505retry_laddr:
506 init_completion(&done);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700507 mutex_lock(&dev->tx_lock);
Sagar Dharia2754ab42012-08-21 18:07:39 -0600508 buf = msm_get_msg_buf(dev, 9);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700509 buf[0] = SLIM_MSG_ASM_FIRST_WORD(9, SLIM_MSG_MT_CORE,
510 SLIM_MSG_MC_ASSIGN_LOGICAL_ADDRESS,
511 SLIM_MSG_DEST_LOGICALADDR,
512 ea[5] | ea[4] << 8);
513 buf[1] = ea[3] | (ea[2] << 8) | (ea[1] << 16) | (ea[0] << 24);
514 buf[2] = laddr;
515
516 dev->wr_comp = &done;
Sagar Dharia2754ab42012-08-21 18:07:39 -0600517 ret = msm_send_msg_buf(dev, buf, 9, MGR_TX_MSG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700518 timeout = wait_for_completion_timeout(&done, HZ);
Sagar Dhariaac913452012-09-04 11:27:26 -0600519 if (!timeout)
520 dev->err = -ETIMEDOUT;
521 if (dev->err) {
522 ret = dev->err;
523 dev->err = 0;
524 dev->wr_comp = NULL;
525 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700526 mutex_unlock(&dev->tx_lock);
Sagar Dhariaac913452012-09-04 11:27:26 -0600527 if (ret) {
528 pr_err("set LADDR:0x%x failed:ret:%d, retrying", laddr, ret);
529 if (retries < INIT_MX_RETRIES) {
530 msm_slim_wait_retry(dev);
531 retries++;
532 goto retry_laddr;
533 } else {
534 pr_err("set LADDR failed after retrying:ret:%d", ret);
535 }
536 }
537 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700538}
539
Sagar Dharia144e5e02011-08-08 17:30:11 -0600540static int msm_clk_pause_wakeup(struct slim_controller *ctrl)
541{
542 struct msm_slim_ctrl *dev = slim_get_ctrldata(ctrl);
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600543 enable_irq(dev->irq);
Sagar Dharia9acf7f42012-03-08 09:45:30 -0700544 clk_prepare_enable(dev->rclk);
Sagar Dharia144e5e02011-08-08 17:30:11 -0600545 writel_relaxed(1, dev->base + FRM_WAKEUP);
546 /* Make sure framer wakeup write goes through before exiting function */
547 mb();
548 /*
549 * Workaround: Currently, slave is reporting lost-sync messages
550 * after slimbus comes out of clock pause.
551 * Transaction with slave fail before slave reports that message
552 * Give some time for that report to come
553 * Slimbus wakes up in clock gear 10 at 24.576MHz. With each superframe
554 * being 250 usecs, we wait for 20 superframes here to ensure
555 * we get the message
556 */
557 usleep_range(5000, 5000);
558 return 0;
559}
560
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700561static int msm_sat_define_ch(struct msm_slim_sat *sat, u8 *buf, u8 len, u8 mc)
562{
563 struct msm_slim_ctrl *dev = sat->dev;
564 enum slim_ch_control oper;
565 int i;
566 int ret = 0;
567 if (mc == SLIM_USR_MC_CHAN_CTRL) {
Sagar Dharia0ffdca12011-09-25 18:55:53 -0600568 for (i = 0; i < sat->nsatch; i++) {
569 if (buf[5] == sat->satch[i].chan)
570 break;
571 }
572 if (i >= sat->nsatch)
573 return -ENOTCONN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700574 oper = ((buf[3] & 0xC0) >> 6);
575 /* part of grp. activating/removing 1 will take care of rest */
Sagar Dharia0ffdca12011-09-25 18:55:53 -0600576 ret = slim_control_ch(&sat->satcl, sat->satch[i].chanh, oper,
577 false);
578 if (!ret) {
579 for (i = 5; i < len; i++) {
580 int j;
581 for (j = 0; j < sat->nsatch; j++) {
582 if (buf[i] == sat->satch[j].chan) {
583 if (oper == SLIM_CH_REMOVE)
584 sat->satch[j].req_rem++;
585 else
586 sat->satch[j].req_def++;
587 break;
588 }
589 }
590 }
591 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700592 } else {
593 u16 chh[40];
594 struct slim_ch prop;
595 u32 exp;
Sagar Dhariab886e042012-10-17 22:41:57 -0600596 u16 *grph = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700597 u8 coeff, cc;
598 u8 prrate = buf[6];
Sagar Dharia0ffdca12011-09-25 18:55:53 -0600599 if (len <= 8)
600 return -EINVAL;
601 for (i = 8; i < len; i++) {
602 int j = 0;
603 for (j = 0; j < sat->nsatch; j++) {
604 if (sat->satch[j].chan == buf[i]) {
605 chh[i - 8] = sat->satch[j].chanh;
606 break;
607 }
608 }
609 if (j < sat->nsatch) {
610 u16 dummy;
611 ret = slim_query_ch(&sat->satcl, buf[i],
612 &dummy);
613 if (ret)
614 return ret;
615 if (mc == SLIM_USR_MC_DEF_ACT_CHAN)
616 sat->satch[j].req_def++;
Sagar Dhariab886e042012-10-17 22:41:57 -0600617 /* First channel in group from satellite */
618 if (i == 8)
619 grph = &sat->satch[j].chanh;
Sagar Dharia0ffdca12011-09-25 18:55:53 -0600620 continue;
621 }
622 if (sat->nsatch >= MSM_MAX_SATCH)
623 return -EXFULL;
624 ret = slim_query_ch(&sat->satcl, buf[i], &chh[i - 8]);
625 if (ret)
626 return ret;
627 sat->satch[j].chan = buf[i];
628 sat->satch[j].chanh = chh[i - 8];
629 if (mc == SLIM_USR_MC_DEF_ACT_CHAN)
630 sat->satch[j].req_def++;
Sagar Dhariab886e042012-10-17 22:41:57 -0600631 if (i == 8)
632 grph = &sat->satch[j].chanh;
Sagar Dharia0ffdca12011-09-25 18:55:53 -0600633 sat->nsatch++;
634 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700635 prop.dataf = (enum slim_ch_dataf)((buf[3] & 0xE0) >> 5);
636 prop.auxf = (enum slim_ch_auxf)((buf[4] & 0xC0) >> 5);
637 prop.baser = SLIM_RATE_4000HZ;
638 if (prrate & 0x8)
639 prop.baser = SLIM_RATE_11025HZ;
640 else
641 prop.baser = SLIM_RATE_4000HZ;
642 prop.prot = (enum slim_ch_proto)(buf[5] & 0x0F);
643 prop.sampleszbits = (buf[4] & 0x1F)*SLIM_CL_PER_SL;
644 exp = (u32)((buf[5] & 0xF0) >> 4);
645 coeff = (buf[4] & 0x20) >> 5;
646 cc = (coeff ? 3 : 1);
647 prop.ratem = cc * (1 << exp);
648 if (i > 9)
649 ret = slim_define_ch(&sat->satcl, &prop, chh, len - 8,
Sagar Dharia0ffdca12011-09-25 18:55:53 -0600650 true, &chh[0]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700651 else
652 ret = slim_define_ch(&sat->satcl, &prop,
Sagar Dhariab886e042012-10-17 22:41:57 -0600653 chh, 1, true, &chh[0]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700654 dev_dbg(dev->dev, "define sat grp returned:%d", ret);
Sagar Dharia0ffdca12011-09-25 18:55:53 -0600655 if (ret)
656 return ret;
Sagar Dhariab886e042012-10-17 22:41:57 -0600657 else if (grph)
658 *grph = chh[0];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700659
660 /* part of group so activating 1 will take care of rest */
661 if (mc == SLIM_USR_MC_DEF_ACT_CHAN)
662 ret = slim_control_ch(&sat->satcl,
Sagar Dharia0ffdca12011-09-25 18:55:53 -0600663 chh[0],
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700664 SLIM_CH_ACTIVATE, false);
665 }
666 return ret;
667}
668
669static void msm_slim_rxwq(struct msm_slim_ctrl *dev)
670{
671 u8 buf[40];
672 u8 mc, mt, len;
673 int i, ret;
674 if ((msm_slim_rx_dequeue(dev, (u8 *)buf)) != -ENODATA) {
675 len = buf[0] & 0x1F;
676 mt = (buf[0] >> 5) & 0x7;
677 mc = buf[1];
678 if (mt == SLIM_MSG_MT_CORE &&
679 mc == SLIM_MSG_MC_REPORT_PRESENT) {
680 u8 laddr;
681 u8 e_addr[6];
682 for (i = 0; i < 6; i++)
683 e_addr[i] = buf[7-i];
684
Sagar Dhariaf0b9c752012-09-09 17:32:46 -0600685 ret = slim_assign_laddr(&dev->ctrl, e_addr, 6, &laddr,
686 false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700687 /* Is this Qualcomm ported generic device? */
688 if (!ret && e_addr[5] == QC_MFGID_LSB &&
689 e_addr[4] == QC_MFGID_MSB &&
690 e_addr[1] == QC_DEVID_PGD &&
691 e_addr[2] != QC_CHIPID_SL)
692 dev->pgdla = laddr;
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600693 if (!ret && !pm_runtime_enabled(dev->dev) &&
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700694 laddr == (QC_MSM_DEVS - 1))
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600695 pm_runtime_enable(dev->dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700696
Sagar Dharia790cfd02011-09-25 17:56:24 -0600697 if (!ret && msm_is_sat_dev(e_addr)) {
698 struct msm_slim_sat *sat = addr_to_sat(dev,
699 laddr);
700 if (!sat)
701 sat = msm_slim_alloc_sat(dev);
702 if (!sat)
703 return;
704
705 sat->satcl.laddr = laddr;
706 msm_sat_enqueue(sat, (u32 *)buf, len);
707 queue_work(sat->wq, &sat->wd);
708 }
Sagar Dhariaac913452012-09-04 11:27:26 -0600709 if (ret)
710 pr_err("assign laddr failed, error:%d", ret);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700711 } else if (mc == SLIM_MSG_MC_REPLY_INFORMATION ||
712 mc == SLIM_MSG_MC_REPLY_VALUE) {
713 u8 tid = buf[3];
714 dev_dbg(dev->dev, "tid:%d, len:%d\n", tid, len - 4);
715 slim_msg_response(&dev->ctrl, &buf[4], tid,
716 len - 4);
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700717 pm_runtime_mark_last_busy(dev->dev);
Sagar Dharia144e5e02011-08-08 17:30:11 -0600718 } else if (mc == SLIM_MSG_MC_REPORT_INFORMATION) {
719 u8 l_addr = buf[2];
720 u16 ele = (u16)buf[4] << 4;
721 ele |= ((buf[3] & 0xf0) >> 4);
722 dev_err(dev->dev, "Slim-dev:%d report inf element:0x%x",
723 l_addr, ele);
724 for (i = 0; i < len - 5; i++)
725 dev_err(dev->dev, "offset:0x%x:bit mask:%x",
726 i, buf[i+5]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700727 } else {
728 dev_err(dev->dev, "unexpected message:mc:%x, mt:%x",
729 mc, mt);
730 for (i = 0; i < len; i++)
731 dev_err(dev->dev, "error msg: %x", buf[i]);
732
733 }
734 } else
735 dev_err(dev->dev, "rxwq called and no dequeue");
736}
737
738static void slim_sat_rxprocess(struct work_struct *work)
739{
740 struct msm_slim_sat *sat = container_of(work, struct msm_slim_sat, wd);
741 struct msm_slim_ctrl *dev = sat->dev;
742 u8 buf[40];
743
744 while ((msm_sat_dequeue(sat, buf)) != -ENODATA) {
745 struct slim_msg_txn txn;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700746 u8 len, mc, mt;
747 u32 bw_sl;
748 int ret = 0;
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700749 int satv = -1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700750 bool gen_ack = false;
751 u8 tid;
752 u8 wbuf[8];
Sagar Dhariaac913452012-09-04 11:27:26 -0600753 int i, retries = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700754 txn.mt = SLIM_MSG_MT_SRC_REFERRED_USER;
755 txn.dt = SLIM_MSG_DEST_LOGICALADDR;
756 txn.ec = 0;
757 txn.rbuf = NULL;
758 txn.la = sat->satcl.laddr;
759 /* satellite handling */
760 len = buf[0] & 0x1F;
761 mc = buf[1];
762 mt = (buf[0] >> 5) & 0x7;
763
764 if (mt == SLIM_MSG_MT_CORE &&
765 mc == SLIM_MSG_MC_REPORT_PRESENT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700766 u8 e_addr[6];
767 for (i = 0; i < 6; i++)
768 e_addr[i] = buf[7-i];
769
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600770 if (pm_runtime_enabled(dev->dev)) {
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700771 satv = msm_slim_get_ctrl(dev);
772 if (satv >= 0)
773 sat->pending_capability = true;
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600774 }
Sagar Dharia69bf5572012-02-21 14:45:35 -0700775 /*
776 * Since capability message is already sent, present
777 * message will indicate subsystem hosting this
778 * satellite has restarted.
779 * Remove all active channels of this satellite
780 * when this is detected
781 */
782 if (sat->sent_capability) {
783 for (i = 0; i < sat->nsatch; i++) {
Sagar Dharia1944a132012-08-15 00:01:57 -0600784 if (sat->satch[i].reconf) {
785 pr_err("SSR, sat:%d, rm ch:%d",
Sagar Dhariaac913452012-09-04 11:27:26 -0600786 sat->satcl.laddr,
Sagar Dharia69bf5572012-02-21 14:45:35 -0700787 sat->satch[i].chan);
Sagar Dharia69bf5572012-02-21 14:45:35 -0700788 slim_control_ch(&sat->satcl,
789 sat->satch[i].chanh,
790 SLIM_CH_REMOVE, true);
Sagar Dhariab886e042012-10-17 22:41:57 -0600791 slim_dealloc_ch(&sat->satcl,
792 sat->satch[i].chanh);
Sagar Dharia1944a132012-08-15 00:01:57 -0600793 sat->satch[i].reconf = false;
794 }
Sagar Dharia69bf5572012-02-21 14:45:35 -0700795 }
796 }
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600797 } else if (mt != SLIM_MSG_MT_CORE &&
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700798 mc != SLIM_MSG_MC_REPORT_PRESENT) {
799 satv = msm_slim_get_ctrl(dev);
800 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700801 switch (mc) {
802 case SLIM_MSG_MC_REPORT_PRESENT:
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600803 /* Remove runtime_pm vote once satellite acks */
804 if (mt != SLIM_MSG_MT_CORE) {
805 if (pm_runtime_enabled(dev->dev) &&
806 sat->pending_capability) {
807 msm_slim_put_ctrl(dev);
808 sat->pending_capability = false;
809 }
810 continue;
811 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700812 /* send a Manager capability msg */
Sagar Dharia790cfd02011-09-25 17:56:24 -0600813 if (sat->sent_capability) {
814 if (mt == SLIM_MSG_MT_CORE)
815 goto send_capability;
816 else
817 continue;
818 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700819 ret = slim_add_device(&dev->ctrl, &sat->satcl);
820 if (ret) {
821 dev_err(dev->dev,
822 "Satellite-init failed");
823 continue;
824 }
Sagar Dharia0ffdca12011-09-25 18:55:53 -0600825 /* Satellite-channels */
826 sat->satch = kzalloc(MSM_MAX_SATCH *
827 sizeof(struct msm_sat_chan),
828 GFP_KERNEL);
Sagar Dharia790cfd02011-09-25 17:56:24 -0600829send_capability:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700830 txn.mc = SLIM_USR_MC_MASTER_CAPABILITY;
831 txn.mt = SLIM_MSG_MT_SRC_REFERRED_USER;
832 txn.la = sat->satcl.laddr;
833 txn.rl = 8;
834 wbuf[0] = SAT_MAGIC_LSB;
835 wbuf[1] = SAT_MAGIC_MSB;
836 wbuf[2] = SAT_MSG_VER;
837 wbuf[3] = SAT_MSG_PROT;
838 txn.wbuf = wbuf;
839 txn.len = 4;
Sagar Dhariaac913452012-09-04 11:27:26 -0600840 ret = msm_xfer_msg(&dev->ctrl, &txn);
841 if (ret) {
842 pr_err("capability for:0x%x fail:%d, retry:%d",
843 sat->satcl.laddr, ret, retries);
844 if (retries < INIT_MX_RETRIES) {
845 msm_slim_wait_retry(dev);
846 retries++;
847 goto send_capability;
848 } else {
849 pr_err("failed after all retries:%d",
850 ret);
851 }
852 } else {
853 sat->sent_capability = true;
854 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700855 break;
856 case SLIM_USR_MC_ADDR_QUERY:
857 memcpy(&wbuf[1], &buf[4], 6);
858 ret = slim_get_logical_addr(&sat->satcl,
859 &wbuf[1], 6, &wbuf[7]);
860 if (ret)
861 memset(&wbuf[1], 0, 6);
862 wbuf[0] = buf[3];
863 txn.mc = SLIM_USR_MC_ADDR_REPLY;
864 txn.rl = 12;
865 txn.len = 8;
866 txn.wbuf = wbuf;
867 msm_xfer_msg(&dev->ctrl, &txn);
868 break;
869 case SLIM_USR_MC_DEFINE_CHAN:
870 case SLIM_USR_MC_DEF_ACT_CHAN:
871 case SLIM_USR_MC_CHAN_CTRL:
872 if (mc != SLIM_USR_MC_CHAN_CTRL)
873 tid = buf[7];
874 else
875 tid = buf[4];
876 gen_ack = true;
877 ret = msm_sat_define_ch(sat, buf, len, mc);
878 if (ret) {
879 dev_err(dev->dev,
880 "SAT define_ch returned:%d",
881 ret);
882 }
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600883 if (!sat->pending_reconf) {
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700884 int chv = msm_slim_get_ctrl(dev);
885 if (chv >= 0)
886 sat->pending_reconf = true;
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600887 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700888 break;
889 case SLIM_USR_MC_RECONFIG_NOW:
890 tid = buf[3];
891 gen_ack = true;
892 ret = slim_reconfigure_now(&sat->satcl);
Sagar Dharia0ffdca12011-09-25 18:55:53 -0600893 for (i = 0; i < sat->nsatch; i++) {
894 struct msm_sat_chan *sch = &sat->satch[i];
Sagar Dhariaef444892012-09-05 12:19:24 -0600895 if (sch->req_rem && sch->reconf) {
Sagar Dharia1944a132012-08-15 00:01:57 -0600896 if (!ret) {
Sagar Dharia0ffdca12011-09-25 18:55:53 -0600897 slim_dealloc_ch(&sat->satcl,
898 sch->chanh);
Sagar Dharia1944a132012-08-15 00:01:57 -0600899 sch->reconf = false;
900 }
Sagar Dharia0ffdca12011-09-25 18:55:53 -0600901 sch->req_rem--;
902 } else if (sch->req_def) {
903 if (ret)
904 slim_dealloc_ch(&sat->satcl,
905 sch->chanh);
Sagar Dharia1944a132012-08-15 00:01:57 -0600906 else
907 sch->reconf = true;
Sagar Dharia0ffdca12011-09-25 18:55:53 -0600908 sch->req_def--;
909 }
910 }
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600911 if (sat->pending_reconf) {
912 msm_slim_put_ctrl(dev);
913 sat->pending_reconf = false;
914 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700915 break;
916 case SLIM_USR_MC_REQ_BW:
917 /* what we get is in SLOTS */
918 bw_sl = (u32)buf[4] << 3 |
919 ((buf[3] & 0xE0) >> 5);
920 sat->satcl.pending_msgsl = bw_sl;
921 tid = buf[5];
922 gen_ack = true;
923 break;
924 case SLIM_USR_MC_CONNECT_SRC:
925 case SLIM_USR_MC_CONNECT_SINK:
926 if (mc == SLIM_USR_MC_CONNECT_SRC)
927 txn.mc = SLIM_MSG_MC_CONNECT_SOURCE;
928 else
929 txn.mc = SLIM_MSG_MC_CONNECT_SINK;
930 wbuf[0] = buf[4] & 0x1F;
931 wbuf[1] = buf[5];
932 tid = buf[6];
933 txn.la = buf[3];
934 txn.mt = SLIM_MSG_MT_CORE;
935 txn.rl = 6;
936 txn.len = 2;
937 txn.wbuf = wbuf;
938 gen_ack = true;
939 ret = msm_xfer_msg(&dev->ctrl, &txn);
940 break;
941 case SLIM_USR_MC_DISCONNECT_PORT:
942 txn.mc = SLIM_MSG_MC_DISCONNECT_PORT;
943 wbuf[0] = buf[4] & 0x1F;
944 tid = buf[5];
945 txn.la = buf[3];
946 txn.rl = 5;
947 txn.len = 1;
948 txn.mt = SLIM_MSG_MT_CORE;
949 txn.wbuf = wbuf;
950 gen_ack = true;
951 ret = msm_xfer_msg(&dev->ctrl, &txn);
Kiran Gunda33a23a92013-01-10 17:03:33 +0530952 break;
953 case SLIM_MSG_MC_REPORT_ABSENT:
954 dev_info(dev->dev, "Received Report Absent Message\n");
955 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700956 default:
957 break;
958 }
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600959 if (!gen_ack) {
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700960 if (mc != SLIM_MSG_MC_REPORT_PRESENT && satv >= 0)
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600961 msm_slim_put_ctrl(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700962 continue;
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600963 }
964
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700965 wbuf[0] = tid;
966 if (!ret)
967 wbuf[1] = MSM_SAT_SUCCSS;
968 else
969 wbuf[1] = 0;
970 txn.mc = SLIM_USR_MC_GENERIC_ACK;
971 txn.la = sat->satcl.laddr;
972 txn.rl = 6;
973 txn.len = 2;
974 txn.wbuf = wbuf;
975 txn.mt = SLIM_MSG_MT_SRC_REFERRED_USER;
976 msm_xfer_msg(&dev->ctrl, &txn);
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700977 if (satv >= 0)
978 msm_slim_put_ctrl(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700979 }
980}
981
Sagar Dharia790cfd02011-09-25 17:56:24 -0600982static struct msm_slim_sat *msm_slim_alloc_sat(struct msm_slim_ctrl *dev)
983{
984 struct msm_slim_sat *sat;
985 char *name;
986 if (dev->nsats >= MSM_MAX_NSATS)
987 return NULL;
988
989 sat = kzalloc(sizeof(struct msm_slim_sat), GFP_KERNEL);
990 if (!sat) {
991 dev_err(dev->dev, "no memory for satellite");
992 return NULL;
993 }
994 name = kzalloc(SLIMBUS_NAME_SIZE, GFP_KERNEL);
995 if (!name) {
996 dev_err(dev->dev, "no memory for satellite name");
997 kfree(sat);
998 return NULL;
999 }
1000 dev->satd[dev->nsats] = sat;
1001 sat->dev = dev;
1002 snprintf(name, SLIMBUS_NAME_SIZE, "msm_sat%d", dev->nsats);
1003 sat->satcl.name = name;
1004 spin_lock_init(&sat->lock);
1005 INIT_WORK(&sat->wd, slim_sat_rxprocess);
1006 sat->wq = create_singlethread_workqueue(sat->satcl.name);
1007 if (!sat->wq) {
1008 kfree(name);
1009 kfree(sat);
1010 return NULL;
1011 }
1012 /*
1013 * Both sats will be allocated from RX thread and RX thread will
1014 * process messages sequentially. No synchronization necessary
1015 */
1016 dev->nsats++;
1017 return sat;
1018}
1019
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001020static int msm_slim_rx_msgq_thread(void *data)
1021{
1022 struct msm_slim_ctrl *dev = (struct msm_slim_ctrl *)data;
1023 struct completion *notify = &dev->rx_msgq_notify;
1024 struct msm_slim_sat *sat = NULL;
1025 u32 mc = 0;
1026 u32 mt = 0;
1027 u32 buffer[10];
1028 int index = 0;
1029 u8 msg_len = 0;
1030 int ret;
1031
1032 dev_dbg(dev->dev, "rx thread started");
1033
1034 while (!kthread_should_stop()) {
1035 set_current_state(TASK_INTERRUPTIBLE);
1036 ret = wait_for_completion_interruptible(notify);
1037
1038 if (ret)
1039 dev_err(dev->dev, "rx thread wait error:%d", ret);
1040
1041 /* 1 irq notification per message */
Sagar Dharia24419e32013-01-14 17:56:32 -07001042 if (dev->use_rx_msgqs != MSM_MSGQ_ENABLED) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001043 msm_slim_rxwq(dev);
1044 continue;
1045 }
1046
1047 ret = msm_slim_rx_msgq_get(dev, buffer, index);
1048 if (ret) {
1049 dev_err(dev->dev, "rx_msgq_get() failed 0x%x\n", ret);
1050 continue;
1051 }
1052
1053 pr_debug("message[%d] = 0x%x\n", index, *buffer);
1054
1055 /* Decide if we use generic RX or satellite RX */
1056 if (index++ == 0) {
1057 msg_len = *buffer & 0x1F;
1058 pr_debug("Start of new message, len = %d\n", msg_len);
1059 mt = (buffer[0] >> 5) & 0x7;
1060 mc = (buffer[0] >> 8) & 0xff;
1061 dev_dbg(dev->dev, "MC: %x, MT: %x\n", mc, mt);
1062 if (mt == SLIM_MSG_MT_DEST_REFERRED_USER ||
Sagar Dharia790cfd02011-09-25 17:56:24 -06001063 mt == SLIM_MSG_MT_SRC_REFERRED_USER) {
1064 u8 laddr;
1065 laddr = (u8)((buffer[0] >> 16) & 0xff);
1066 sat = addr_to_sat(dev, laddr);
1067 }
Kiran Gunda33a23a92013-01-10 17:03:33 +05301068 }
1069 if ((index * 4) >= msg_len) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001070 index = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001071 if (sat) {
1072 msm_sat_enqueue(sat, buffer, msg_len);
1073 queue_work(sat->wq, &sat->wd);
1074 sat = NULL;
1075 } else {
1076 msm_slim_rx_enqueue(dev, buffer, msg_len);
1077 msm_slim_rxwq(dev);
1078 }
1079 }
1080 }
1081
1082 return 0;
1083}
1084
Sagar Dhariacc969452011-09-19 10:34:30 -06001085static void msm_slim_prg_slew(struct platform_device *pdev,
1086 struct msm_slim_ctrl *dev)
1087{
1088 struct resource *slew_io;
1089 void __iomem *slew_reg;
1090 /* SLEW RATE register for this slimbus */
1091 dev->slew_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
1092 "slimbus_slew_reg");
1093 if (!dev->slew_mem) {
1094 dev_dbg(&pdev->dev, "no slimbus slew resource\n");
1095 return;
1096 }
1097 slew_io = request_mem_region(dev->slew_mem->start,
1098 resource_size(dev->slew_mem), pdev->name);
1099 if (!slew_io) {
1100 dev_dbg(&pdev->dev, "slimbus-slew mem claimed\n");
1101 dev->slew_mem = NULL;
1102 return;
1103 }
1104
1105 slew_reg = ioremap(dev->slew_mem->start, resource_size(dev->slew_mem));
1106 if (!slew_reg) {
1107 dev_dbg(dev->dev, "slew register mapping failed");
1108 release_mem_region(dev->slew_mem->start,
1109 resource_size(dev->slew_mem));
1110 dev->slew_mem = NULL;
1111 return;
1112 }
1113 writel_relaxed(1, slew_reg);
1114 /* Make sure slimbus-slew rate enabling goes through */
1115 wmb();
1116 iounmap(slew_reg);
1117}
1118
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001119static int __devinit msm_slim_probe(struct platform_device *pdev)
1120{
1121 struct msm_slim_ctrl *dev;
1122 int ret;
Joonwoo Parkf69f77a2012-08-28 15:26:11 -07001123 enum apr_subsys_state q6_state;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001124 struct resource *bam_mem, *bam_io;
1125 struct resource *slim_mem, *slim_io;
1126 struct resource *irq, *bam_irq;
Sagar Dharia1beb2202012-07-31 19:06:21 -06001127 bool rxreg_access = false;
Joonwoo Parkf69f77a2012-08-28 15:26:11 -07001128
1129 q6_state = apr_get_q6_state();
1130 if (q6_state == APR_SUBSYS_DOWN) {
1131 dev_dbg(&pdev->dev, "defering %s, adsp_state %d\n", __func__,
1132 q6_state);
1133 return -EPROBE_DEFER;
1134 } else
1135 dev_dbg(&pdev->dev, "adsp is ready\n");
1136
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001137 slim_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
1138 "slimbus_physical");
1139 if (!slim_mem) {
1140 dev_err(&pdev->dev, "no slimbus physical memory resource\n");
1141 return -ENODEV;
1142 }
1143 slim_io = request_mem_region(slim_mem->start, resource_size(slim_mem),
1144 pdev->name);
1145 if (!slim_io) {
1146 dev_err(&pdev->dev, "slimbus memory already claimed\n");
1147 return -EBUSY;
1148 }
1149
1150 bam_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
1151 "slimbus_bam_physical");
1152 if (!bam_mem) {
1153 dev_err(&pdev->dev, "no slimbus BAM memory resource\n");
1154 ret = -ENODEV;
1155 goto err_get_res_bam_failed;
1156 }
1157 bam_io = request_mem_region(bam_mem->start, resource_size(bam_mem),
1158 pdev->name);
1159 if (!bam_io) {
1160 release_mem_region(slim_mem->start, resource_size(slim_mem));
1161 dev_err(&pdev->dev, "slimbus BAM memory already claimed\n");
1162 ret = -EBUSY;
1163 goto err_get_res_bam_failed;
1164 }
1165 irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
1166 "slimbus_irq");
1167 if (!irq) {
1168 dev_err(&pdev->dev, "no slimbus IRQ resource\n");
1169 ret = -ENODEV;
1170 goto err_get_res_failed;
1171 }
1172 bam_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
1173 "slimbus_bam_irq");
1174 if (!bam_irq) {
1175 dev_err(&pdev->dev, "no slimbus BAM IRQ resource\n");
1176 ret = -ENODEV;
1177 goto err_get_res_failed;
1178 }
1179
1180 dev = kzalloc(sizeof(struct msm_slim_ctrl), GFP_KERNEL);
1181 if (!dev) {
1182 dev_err(&pdev->dev, "no memory for MSM slimbus controller\n");
1183 ret = -ENOMEM;
1184 goto err_get_res_failed;
1185 }
1186 dev->dev = &pdev->dev;
1187 platform_set_drvdata(pdev, dev);
1188 slim_set_ctrldata(&dev->ctrl, dev);
1189 dev->base = ioremap(slim_mem->start, resource_size(slim_mem));
1190 if (!dev->base) {
1191 dev_err(&pdev->dev, "IOremap failed\n");
1192 ret = -ENOMEM;
1193 goto err_ioremap_failed;
1194 }
1195 dev->bam.base = ioremap(bam_mem->start, resource_size(bam_mem));
1196 if (!dev->bam.base) {
1197 dev_err(&pdev->dev, "BAM IOremap failed\n");
1198 ret = -ENOMEM;
1199 goto err_ioremap_bam_failed;
1200 }
Sagar Dhariaf8f603b2012-03-21 15:25:17 -06001201 if (pdev->dev.of_node) {
1202
1203 ret = of_property_read_u32(pdev->dev.of_node, "cell-index",
1204 &dev->ctrl.nr);
1205 if (ret) {
1206 dev_err(&pdev->dev, "Cell index not specified:%d", ret);
1207 goto err_of_init_failed;
1208 }
Sagar Dharia1beb2202012-07-31 19:06:21 -06001209 rxreg_access = of_property_read_bool(pdev->dev.of_node,
1210 "qcom,rxreg-access");
Sagar Dhariaf8f603b2012-03-21 15:25:17 -06001211 /* Optional properties */
1212 ret = of_property_read_u32(pdev->dev.of_node,
1213 "qcom,min-clk-gear", &dev->ctrl.min_cg);
1214 ret = of_property_read_u32(pdev->dev.of_node,
1215 "qcom,max-clk-gear", &dev->ctrl.max_cg);
Sagar Dharia1beb2202012-07-31 19:06:21 -06001216 pr_debug("min_cg:%d, max_cg:%d, rxreg: %d", dev->ctrl.min_cg,
1217 dev->ctrl.max_cg, rxreg_access);
Sagar Dhariaf8f603b2012-03-21 15:25:17 -06001218 } else {
1219 dev->ctrl.nr = pdev->id;
1220 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001221 dev->ctrl.nchans = MSM_SLIM_NCHANS;
1222 dev->ctrl.nports = MSM_SLIM_NPORTS;
1223 dev->ctrl.set_laddr = msm_set_laddr;
1224 dev->ctrl.xfer_msg = msm_xfer_msg;
Sagar Dharia144e5e02011-08-08 17:30:11 -06001225 dev->ctrl.wakeup = msm_clk_pause_wakeup;
Sagar Dharia100e7212013-05-17 18:20:57 -06001226 dev->ctrl.alloc_port = msm_alloc_port;
1227 dev->ctrl.dealloc_port = msm_dealloc_port;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001228 dev->ctrl.port_xfer = msm_slim_port_xfer;
1229 dev->ctrl.port_xfer_status = msm_slim_port_xfer_status;
1230 /* Reserve some messaging BW for satellite-apps driver communication */
1231 dev->ctrl.sched.pending_msgsl = 30;
1232
1233 init_completion(&dev->reconf);
1234 mutex_init(&dev->tx_lock);
1235 spin_lock_init(&dev->rx_lock);
1236 dev->ee = 1;
Sagar Dharia1beb2202012-07-31 19:06:21 -06001237 if (rxreg_access)
Sagar Dharia24419e32013-01-14 17:56:32 -07001238 dev->use_rx_msgqs = MSM_MSGQ_DISABLED;
Sagar Dharia1beb2202012-07-31 19:06:21 -06001239 else
Sagar Dharia24419e32013-01-14 17:56:32 -07001240 dev->use_rx_msgqs = MSM_MSGQ_RESET;
Sagar Dharia1beb2202012-07-31 19:06:21 -06001241
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001242 dev->irq = irq->start;
1243 dev->bam.irq = bam_irq->start;
1244
Sagar Dhariadebc8b72012-08-11 15:02:12 -06001245 dev->hclk = clk_get(dev->dev, "iface_clk");
1246 if (IS_ERR(dev->hclk))
1247 dev->hclk = NULL;
1248 else
1249 clk_prepare_enable(dev->hclk);
1250
Sagar Dharia60f59a72012-10-17 12:42:03 -06001251 ret = msm_slim_sps_init(dev, bam_mem, MGR_STATUS, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001252 if (ret != 0) {
1253 dev_err(dev->dev, "error SPS init\n");
1254 goto err_sps_init_failed;
1255 }
1256
Sagar Dharia2754ab42012-08-21 18:07:39 -06001257 /* Fire up the Rx message queue thread */
1258 dev->rx_msgq_thread = kthread_run(msm_slim_rx_msgq_thread, dev,
1259 MSM_SLIM_NAME "_rx_msgq_thread");
1260 if (IS_ERR(dev->rx_msgq_thread)) {
1261 ret = PTR_ERR(dev->rx_msgq_thread);
1262 dev_err(dev->dev, "Failed to start Rx message queue thread\n");
1263 goto err_thread_create_failed;
1264 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001265
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001266 dev->framer.rootfreq = SLIM_ROOT_FREQ >> 3;
1267 dev->framer.superfreq =
1268 dev->framer.rootfreq / SLIM_CL_PER_SUPERFRAME_DIV8;
1269 dev->ctrl.a_framer = &dev->framer;
1270 dev->ctrl.clkgear = SLIM_MAX_CLK_GEAR;
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001271 dev->ctrl.dev.parent = &pdev->dev;
Sagar Dhariaf8f603b2012-03-21 15:25:17 -06001272 dev->ctrl.dev.of_node = pdev->dev.of_node;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001273
1274 ret = request_irq(dev->irq, msm_slim_interrupt, IRQF_TRIGGER_HIGH,
1275 "msm_slim_irq", dev);
1276 if (ret) {
1277 dev_err(&pdev->dev, "request IRQ failed\n");
1278 goto err_request_irq_failed;
1279 }
1280
Sagar Dhariacc969452011-09-19 10:34:30 -06001281 msm_slim_prg_slew(pdev, dev);
Sagar Dhariab1c0acf2012-02-06 18:16:58 -07001282
1283 /* Register with framework before enabling frame, clock */
1284 ret = slim_add_numbered_controller(&dev->ctrl);
1285 if (ret) {
1286 dev_err(dev->dev, "error adding controller\n");
1287 goto err_ctrl_failed;
1288 }
1289
1290
Tianyi Gou44a81b02012-02-06 17:49:07 -08001291 dev->rclk = clk_get(dev->dev, "core_clk");
Sagar Dhariab1c0acf2012-02-06 18:16:58 -07001292 if (!dev->rclk) {
1293 dev_err(dev->dev, "slimbus clock not found");
1294 goto err_clk_get_failed;
1295 }
Sagar Dhariacc969452011-09-19 10:34:30 -06001296 clk_set_rate(dev->rclk, SLIM_ROOT_FREQ);
Sagar Dharia9acf7f42012-03-08 09:45:30 -07001297 clk_prepare_enable(dev->rclk);
Sagar Dhariacc969452011-09-19 10:34:30 -06001298
Sagar Dharia82e516f2012-03-16 16:01:23 -06001299 dev->ver = readl_relaxed(dev->base);
1300 /* Version info in 16 MSbits */
1301 dev->ver >>= 16;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001302 /* Component register initialization */
Sagar Dharia82e516f2012-03-16 16:01:23 -06001303 writel_relaxed(1, dev->base + CFG_PORT(COMP_CFG, dev->ver));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001304 writel_relaxed((EE_MGR_RSC_GRP | EE_NGD_2 | EE_NGD_1),
Sagar Dharia82e516f2012-03-16 16:01:23 -06001305 dev->base + CFG_PORT(COMP_TRUST_CFG, dev->ver));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001306
1307 /*
1308 * Manager register initialization
1309 * If RX msg Q is used, disable RX_MSG_RCVD interrupt
1310 */
Sagar Dharia24419e32013-01-14 17:56:32 -07001311 if (dev->use_rx_msgqs == MSM_MSGQ_ENABLED)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001312 writel_relaxed((MGR_INT_RECFG_DONE | MGR_INT_TX_NACKED_2 |
1313 MGR_INT_MSG_BUF_CONTE | /* MGR_INT_RX_MSG_RCVD | */
1314 MGR_INT_TX_MSG_SENT), dev->base + MGR_INT_EN);
1315 else
1316 writel_relaxed((MGR_INT_RECFG_DONE | MGR_INT_TX_NACKED_2 |
1317 MGR_INT_MSG_BUF_CONTE | MGR_INT_RX_MSG_RCVD |
1318 MGR_INT_TX_MSG_SENT), dev->base + MGR_INT_EN);
1319 writel_relaxed(1, dev->base + MGR_CFG);
1320 /*
1321 * Framer registers are beyond 1K memory region after Manager and/or
1322 * component registers. Make sure those writes are ordered
1323 * before framer register writes
1324 */
1325 wmb();
1326
1327 /* Framer register initialization */
Sagar Dhariadebc8b72012-08-11 15:02:12 -06001328 writel_relaxed((1 << INTR_WAKE) | (0xA << REF_CLK_GEAR) |
1329 (0xA << CLK_GEAR) | (1 << ROOT_FREQ) | (1 << FRM_ACTIVE) | 1,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001330 dev->base + FRM_CFG);
1331 /*
1332 * Make sure that framer wake-up and enabling writes go through
1333 * before any other component is enabled. Framer is responsible for
1334 * clocking the bus and enabling framer first will ensure that other
1335 * devices can report presence when they are enabled
1336 */
1337 mb();
1338
1339 /* Enable RX msg Q */
Sagar Dharia24419e32013-01-14 17:56:32 -07001340 if (dev->use_rx_msgqs == MSM_MSGQ_ENABLED)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001341 writel_relaxed(MGR_CFG_ENABLE | MGR_CFG_RX_MSGQ_EN,
1342 dev->base + MGR_CFG);
1343 else
1344 writel_relaxed(MGR_CFG_ENABLE, dev->base + MGR_CFG);
1345 /*
1346 * Make sure that manager-enable is written through before interface
1347 * device is enabled
1348 */
1349 mb();
1350 writel_relaxed(1, dev->base + INTF_CFG);
1351 /*
1352 * Make sure that interface-enable is written through before enabling
1353 * ported generic device inside MSM manager
1354 */
1355 mb();
Sagar Dharia82e516f2012-03-16 16:01:23 -06001356 writel_relaxed(1, dev->base + CFG_PORT(PGD_CFG, dev->ver));
1357 writel_relaxed(0x3F<<17, dev->base + CFG_PORT(PGD_OWN_EEn, dev->ver) +
1358 (4 * dev->ee));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001359 /*
1360 * Make sure that ported generic device is enabled and port-EE settings
1361 * are written through before finally enabling the component
1362 */
1363 mb();
1364
Sagar Dharia82e516f2012-03-16 16:01:23 -06001365 writel_relaxed(1, dev->base + CFG_PORT(COMP_CFG, dev->ver));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001366 /*
1367 * Make sure that all writes have gone through before exiting this
1368 * function
1369 */
1370 mb();
Sagar Dhariaa6627e02012-08-28 12:20:49 -06001371
1372 /* Add devices registered with board-info now that controller is up */
1373 slim_ctrl_add_boarddevs(&dev->ctrl);
1374
Sagar Dhariaf8f603b2012-03-21 15:25:17 -06001375 if (pdev->dev.of_node)
1376 of_register_slim_devices(&dev->ctrl);
1377
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001378 pm_runtime_use_autosuspend(&pdev->dev);
1379 pm_runtime_set_autosuspend_delay(&pdev->dev, MSM_SLIM_AUTOSUSPEND);
1380 pm_runtime_set_active(&pdev->dev);
1381
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001382 dev_dbg(dev->dev, "MSM SB controller is up!\n");
1383 return 0;
1384
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001385err_ctrl_failed:
Sagar Dharia82e516f2012-03-16 16:01:23 -06001386 writel_relaxed(0, dev->base + CFG_PORT(COMP_CFG, dev->ver));
Sagar Dhariab1c0acf2012-02-06 18:16:58 -07001387err_clk_get_failed:
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001388 kfree(dev->satd);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001389err_request_irq_failed:
Sagar Dharia2754ab42012-08-21 18:07:39 -06001390 kthread_stop(dev->rx_msgq_thread);
1391err_thread_create_failed:
Sagar Dharia33beca02012-10-22 16:21:46 -06001392 msm_slim_sps_exit(dev, true);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001393err_sps_init_failed:
Sagar Dhariadebc8b72012-08-11 15:02:12 -06001394 if (dev->hclk) {
1395 clk_disable_unprepare(dev->hclk);
1396 clk_put(dev->hclk);
1397 }
Sagar Dhariaf8f603b2012-03-21 15:25:17 -06001398err_of_init_failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001399 iounmap(dev->bam.base);
1400err_ioremap_bam_failed:
1401 iounmap(dev->base);
1402err_ioremap_failed:
1403 kfree(dev);
1404err_get_res_failed:
1405 release_mem_region(bam_mem->start, resource_size(bam_mem));
1406err_get_res_bam_failed:
1407 release_mem_region(slim_mem->start, resource_size(slim_mem));
1408 return ret;
1409}
1410
1411static int __devexit msm_slim_remove(struct platform_device *pdev)
1412{
1413 struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
1414 struct resource *bam_mem;
1415 struct resource *slim_mem;
Sagar Dhariacc969452011-09-19 10:34:30 -06001416 struct resource *slew_mem = dev->slew_mem;
Sagar Dharia790cfd02011-09-25 17:56:24 -06001417 int i;
1418 for (i = 0; i < dev->nsats; i++) {
1419 struct msm_slim_sat *sat = dev->satd[i];
Sagar Dharia0ffdca12011-09-25 18:55:53 -06001420 int j;
1421 for (j = 0; j < sat->nsatch; j++)
1422 slim_dealloc_ch(&sat->satcl, sat->satch[j].chanh);
Sagar Dharia790cfd02011-09-25 17:56:24 -06001423 slim_remove_device(&sat->satcl);
1424 kfree(sat->satch);
1425 destroy_workqueue(sat->wq);
1426 kfree(sat->satcl.name);
1427 kfree(sat);
1428 }
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001429 pm_runtime_disable(&pdev->dev);
1430 pm_runtime_set_suspended(&pdev->dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001431 free_irq(dev->irq, dev);
1432 slim_del_controller(&dev->ctrl);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001433 clk_put(dev->rclk);
Sagar Dhariadebc8b72012-08-11 15:02:12 -06001434 if (dev->hclk)
1435 clk_put(dev->hclk);
Sagar Dharia33beca02012-10-22 16:21:46 -06001436 msm_slim_sps_exit(dev, true);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001437 kthread_stop(dev->rx_msgq_thread);
1438 iounmap(dev->bam.base);
1439 iounmap(dev->base);
1440 kfree(dev);
1441 bam_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
1442 "slimbus_bam_physical");
Sagar Dhariae77961f2011-09-27 14:03:50 -06001443 if (bam_mem)
1444 release_mem_region(bam_mem->start, resource_size(bam_mem));
Sagar Dhariacc969452011-09-19 10:34:30 -06001445 if (slew_mem)
1446 release_mem_region(slew_mem->start, resource_size(slew_mem));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001447 slim_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
1448 "slimbus_physical");
Sagar Dhariae77961f2011-09-27 14:03:50 -06001449 if (slim_mem)
1450 release_mem_region(slim_mem->start, resource_size(slim_mem));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001451 return 0;
1452}
1453
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001454#ifdef CONFIG_PM_RUNTIME
1455static int msm_slim_runtime_idle(struct device *device)
1456{
Sagar Dhariad1468b72013-07-16 12:56:22 -06001457 struct platform_device *pdev = to_platform_device(device);
1458 struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
1459 if (dev->state == MSM_CTRL_AWAKE)
1460 dev->state = MSM_CTRL_IDLE;
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001461 dev_dbg(device, "pm_runtime: idle...\n");
1462 pm_request_autosuspend(device);
1463 return -EAGAIN;
1464}
1465#endif
1466
1467/*
1468 * If PM_RUNTIME is not defined, these 2 functions become helper
1469 * functions to be called from system suspend/resume. So they are not
1470 * inside ifdef CONFIG_PM_RUNTIME
1471 */
Sagar Dharia45e77912012-01-10 09:55:18 -07001472#ifdef CONFIG_PM_SLEEP
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001473static int msm_slim_runtime_suspend(struct device *device)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001474{
1475 struct platform_device *pdev = to_platform_device(device);
1476 struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001477 int ret;
1478 dev_dbg(device, "pm_runtime: suspending...\n");
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001479 ret = slim_ctrl_clk_pause(&dev->ctrl, false, SLIM_CLK_UNSPECIFIED);
Sagar Dhariad3ef30a2011-12-09 14:30:45 -07001480 if (ret) {
1481 dev_err(device, "clk pause not entered:%d", ret);
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001482 dev->state = MSM_CTRL_AWAKE;
Sagar Dhariad3ef30a2011-12-09 14:30:45 -07001483 } else {
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001484 dev->state = MSM_CTRL_ASLEEP;
Sagar Dhariad3ef30a2011-12-09 14:30:45 -07001485 }
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001486 return ret;
1487}
1488
1489static int msm_slim_runtime_resume(struct device *device)
1490{
1491 struct platform_device *pdev = to_platform_device(device);
1492 struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
1493 int ret = 0;
1494 dev_dbg(device, "pm_runtime: resuming...\n");
1495 if (dev->state == MSM_CTRL_ASLEEP)
1496 ret = slim_ctrl_clk_pause(&dev->ctrl, true, 0);
Sagar Dhariad3ef30a2011-12-09 14:30:45 -07001497 if (ret) {
1498 dev_err(device, "clk pause not exited:%d", ret);
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001499 dev->state = MSM_CTRL_ASLEEP;
Sagar Dhariad3ef30a2011-12-09 14:30:45 -07001500 } else {
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001501 dev->state = MSM_CTRL_AWAKE;
Sagar Dhariad3ef30a2011-12-09 14:30:45 -07001502 }
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001503 return ret;
1504}
1505
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001506static int msm_slim_suspend(struct device *dev)
1507{
Sagar Dhariad1468b72013-07-16 12:56:22 -06001508 int ret = -EBUSY;
1509 struct platform_device *pdev = to_platform_device(dev);
1510 struct msm_slim_ctrl *cdev = platform_get_drvdata(pdev);
1511 if (!pm_runtime_enabled(dev) ||
1512 (!pm_runtime_suspended(dev) &&
1513 cdev->state == MSM_CTRL_IDLE)) {
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001514 dev_dbg(dev, "system suspend");
1515 ret = msm_slim_runtime_suspend(dev);
Sagar Dhariadebc8b72012-08-11 15:02:12 -06001516 if (!ret) {
1517 if (cdev->hclk)
1518 clk_disable_unprepare(cdev->hclk);
1519 }
Sagar Dharia6b559e02011-08-03 17:01:31 -06001520 }
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001521 if (ret == -EBUSY) {
Sagar Dharia144e5e02011-08-08 17:30:11 -06001522 /*
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001523 * If the clock pause failed due to active channels, there is
1524 * a possibility that some audio stream is active during suspend
1525 * We dont want to return suspend failure in that case so that
1526 * display and relevant components can still go to suspend.
1527 * If there is some other error, then it should be passed-on
1528 * to system level suspend
1529 */
Sagar Dharia144e5e02011-08-08 17:30:11 -06001530 ret = 0;
1531 }
1532 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001533}
1534
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001535static int msm_slim_resume(struct device *dev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001536{
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001537 /* If runtime_pm is enabled, this resume shouldn't do anything */
1538 if (!pm_runtime_enabled(dev) || !pm_runtime_suspended(dev)) {
Sagar Dhariadebc8b72012-08-11 15:02:12 -06001539 struct platform_device *pdev = to_platform_device(dev);
1540 struct msm_slim_ctrl *cdev = platform_get_drvdata(pdev);
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001541 int ret;
1542 dev_dbg(dev, "system resume");
Sagar Dhariadebc8b72012-08-11 15:02:12 -06001543 if (cdev->hclk)
1544 clk_prepare_enable(cdev->hclk);
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001545 ret = msm_slim_runtime_resume(dev);
1546 if (!ret) {
1547 pm_runtime_mark_last_busy(dev);
1548 pm_request_autosuspend(dev);
1549 }
1550 return ret;
1551
Sagar Dharia144e5e02011-08-08 17:30:11 -06001552 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001553 return 0;
1554}
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001555#endif /* CONFIG_PM_SLEEP */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001556
1557static const struct dev_pm_ops msm_slim_dev_pm_ops = {
1558 SET_SYSTEM_SLEEP_PM_OPS(
1559 msm_slim_suspend,
1560 msm_slim_resume
1561 )
1562 SET_RUNTIME_PM_OPS(
1563 msm_slim_runtime_suspend,
1564 msm_slim_runtime_resume,
1565 msm_slim_runtime_idle
1566 )
1567};
1568
Sagar Dhariaf8f603b2012-03-21 15:25:17 -06001569static struct of_device_id msm_slim_dt_match[] = {
1570 {
1571 .compatible = "qcom,slim-msm",
1572 },
1573 {}
1574};
1575
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001576static struct platform_driver msm_slim_driver = {
1577 .probe = msm_slim_probe,
1578 .remove = msm_slim_remove,
1579 .driver = {
1580 .name = MSM_SLIM_NAME,
1581 .owner = THIS_MODULE,
1582 .pm = &msm_slim_dev_pm_ops,
Sagar Dhariaf8f603b2012-03-21 15:25:17 -06001583 .of_match_table = msm_slim_dt_match,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001584 },
1585};
1586
1587static int msm_slim_init(void)
1588{
1589 return platform_driver_register(&msm_slim_driver);
1590}
1591subsys_initcall(msm_slim_init);
1592
1593static void msm_slim_exit(void)
1594{
1595 platform_driver_unregister(&msm_slim_driver);
1596}
1597module_exit(msm_slim_exit);
1598
1599MODULE_LICENSE("GPL v2");
1600MODULE_VERSION("0.1");
1601MODULE_DESCRIPTION("MSM Slimbus controller");
1602MODULE_ALIAS("platform:msm-slim");