blob: 924a02885484c6eb8ae971c749cfe2517a4f8d9c [file] [log] [blame]
Sagar Dharia8554f152014-04-01 15:36:15 -06001/* Copyright (c) 2011-2014, 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();
Sagar Dharia8554f152014-04-01 15:36:15 -0600210 msm_slim_manage_tx_msgq(dev, false, NULL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700211 }
212 if (stat & MGR_INT_RX_MSG_RCVD) {
213 u32 rx_buf[10];
214 u32 mc, mt;
215 u8 len, i;
216 rx_buf[0] = readl_relaxed(dev->base + MGR_RX_MSG);
217 len = rx_buf[0] & 0x1F;
218 for (i = 1; i < ((len + 3) >> 2); i++) {
219 rx_buf[i] = readl_relaxed(dev->base + MGR_RX_MSG +
220 (4 * i));
221 dev_dbg(dev->dev, "reading data: %x\n", rx_buf[i]);
222 }
223 mt = (rx_buf[0] >> 5) & 0x7;
224 mc = (rx_buf[0] >> 8) & 0xff;
225 dev_dbg(dev->dev, "MC: %x, MT: %x\n", mc, mt);
226 if (mt == SLIM_MSG_MT_DEST_REFERRED_USER ||
227 mt == SLIM_MSG_MT_SRC_REFERRED_USER) {
Sagar Dharia790cfd02011-09-25 17:56:24 -0600228 u8 laddr = (u8)((rx_buf[0] >> 16) & 0xFF);
229 struct msm_slim_sat *sat = addr_to_sat(dev, laddr);
230 if (sat)
231 msm_sat_enqueue(sat, rx_buf, len);
232 else
233 dev_err(dev->dev, "unknown sat:%d message",
234 laddr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700235 writel_relaxed(MGR_INT_RX_MSG_RCVD,
236 dev->base + MGR_INT_CLR);
237 /*
238 * Guarantee that CLR bit write goes through before
239 * queuing work
240 */
241 mb();
Sagar Dharia790cfd02011-09-25 17:56:24 -0600242 if (sat)
243 queue_work(sat->wq, &sat->wd);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700244 } else if (mt == SLIM_MSG_MT_CORE &&
245 mc == SLIM_MSG_MC_REPORT_PRESENT) {
246 u8 e_addr[6];
247 msm_get_eaddr(e_addr, rx_buf);
Sagar Dharia790cfd02011-09-25 17:56:24 -0600248 msm_slim_rx_enqueue(dev, rx_buf, len);
249 writel_relaxed(MGR_INT_RX_MSG_RCVD, dev->base +
250 MGR_INT_CLR);
251 /*
252 * Guarantee that CLR bit write goes through
253 * before signalling completion
254 */
255 mb();
256 complete(&dev->rx_msgq_notify);
Kiran Gunda33a23a92013-01-10 17:03:33 +0530257 } else if (mt == SLIM_MSG_MT_CORE &&
258 mc == SLIM_MSG_MC_REPORT_ABSENT) {
259 writel_relaxed(MGR_INT_RX_MSG_RCVD, dev->base +
260 MGR_INT_CLR);
261 /*
262 * Guarantee that CLR bit write goes through
263 * before signalling completion
264 */
265 mb();
266 complete(&dev->rx_msgq_notify);
267
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700268 } else if (mc == SLIM_MSG_MC_REPLY_INFORMATION ||
269 mc == SLIM_MSG_MC_REPLY_VALUE) {
270 msm_slim_rx_enqueue(dev, rx_buf, len);
271 writel_relaxed(MGR_INT_RX_MSG_RCVD, dev->base +
272 MGR_INT_CLR);
273 /*
274 * Guarantee that CLR bit write goes through
275 * before signalling completion
276 */
277 mb();
278 complete(&dev->rx_msgq_notify);
Sagar Dharia144e5e02011-08-08 17:30:11 -0600279 } else if (mc == SLIM_MSG_MC_REPORT_INFORMATION) {
280 u8 *buf = (u8 *)rx_buf;
281 u8 l_addr = buf[2];
282 u16 ele = (u16)buf[4] << 4;
283 ele |= ((buf[3] & 0xf0) >> 4);
284 dev_err(dev->dev, "Slim-dev:%d report inf element:0x%x",
285 l_addr, ele);
286 for (i = 0; i < len - 5; i++)
287 dev_err(dev->dev, "offset:0x%x:bit mask:%x",
288 i, buf[i+5]);
289 writel_relaxed(MGR_INT_RX_MSG_RCVD, dev->base +
290 MGR_INT_CLR);
291 /*
292 * Guarantee that CLR bit write goes through
293 * before exiting
294 */
295 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700296 } else {
297 dev_err(dev->dev, "Unexpected MC,%x MT:%x, len:%d",
298 mc, mt, len);
299 for (i = 0; i < ((len + 3) >> 2); i++)
300 dev_err(dev->dev, "error msg: %x", rx_buf[i]);
301 writel_relaxed(MGR_INT_RX_MSG_RCVD, dev->base +
302 MGR_INT_CLR);
303 /*
304 * Guarantee that CLR bit write goes through
305 * before exiting
306 */
307 mb();
308 }
309 }
310 if (stat & MGR_INT_RECFG_DONE) {
311 writel_relaxed(MGR_INT_RECFG_DONE, dev->base + MGR_INT_CLR);
312 /*
313 * Guarantee that CLR bit write goes through
314 * before exiting ISR
315 */
316 mb();
317 complete(&dev->reconf);
318 }
Sagar Dharia82e516f2012-03-16 16:01:23 -0600319 pstat = readl_relaxed(PGD_THIS_EE(PGD_PORT_INT_ST_EEn, dev->ver));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700320 if (pstat != 0) {
Sagar Dharia2b8a4b52013-05-15 20:01:45 -0600321 return msm_slim_port_irq_handler(dev, pstat);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700322 }
323
324 return IRQ_HANDLED;
325}
326
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700327static int msm_xfer_msg(struct slim_controller *ctrl, struct slim_msg_txn *txn)
328{
329 DECLARE_COMPLETION_ONSTACK(done);
330 struct msm_slim_ctrl *dev = slim_get_ctrldata(ctrl);
331 u32 *pbuf;
332 u8 *puc;
333 int timeout;
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700334 int msgv = -1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700335 u8 la = txn->la;
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600336 u8 mc = (u8)(txn->mc & 0xFF);
337 /*
338 * Voting for runtime PM: Slimbus has 2 possible use cases:
339 * 1. messaging
340 * 2. Data channels
341 * Messaging case goes through messaging slots and data channels
342 * use their own slots
343 * This "get" votes for messaging bandwidth
344 */
345 if (!(txn->mc & SLIM_MSG_CLK_PAUSE_SEQ_FLG))
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700346 msgv = msm_slim_get_ctrl(dev);
Sagar Dhariad1468b72013-07-16 12:56:22 -0600347 if (msgv >= 0)
348 dev->state = MSM_CTRL_AWAKE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700349 mutex_lock(&dev->tx_lock);
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700350 if (dev->state == MSM_CTRL_ASLEEP ||
351 ((!(txn->mc & SLIM_MSG_CLK_PAUSE_SEQ_FLG)) &&
Sagar Dhariad1468b72013-07-16 12:56:22 -0600352 dev->state == MSM_CTRL_IDLE)) {
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600353 dev_err(dev->dev, "runtime or system PM suspended state");
354 mutex_unlock(&dev->tx_lock);
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700355 if (msgv >= 0)
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600356 msm_slim_put_ctrl(dev);
357 return -EBUSY;
358 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700359 if (txn->mt == SLIM_MSG_MT_CORE &&
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600360 mc == SLIM_MSG_MC_BEGIN_RECONFIGURATION) {
361 if (dev->reconf_busy) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700362 wait_for_completion(&dev->reconf);
363 dev->reconf_busy = false;
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600364 }
365 /* This "get" votes for data channels */
366 if (dev->ctrl.sched.usedslots != 0 &&
367 !dev->chan_active) {
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700368 int chv = msm_slim_get_ctrl(dev);
369 if (chv >= 0)
370 dev->chan_active = true;
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600371 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700372 }
373 txn->rl--;
Sagar Dharia8554f152014-04-01 15:36:15 -0600374 pbuf = msm_get_msg_buf(dev, txn->rl, &done);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700375 dev->err = 0;
376
377 if (txn->dt == SLIM_MSG_DEST_ENUMADDR) {
378 mutex_unlock(&dev->tx_lock);
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700379 if (msgv >= 0)
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600380 msm_slim_put_ctrl(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700381 return -EPROTONOSUPPORT;
382 }
383 if (txn->mt == SLIM_MSG_MT_CORE && txn->la == 0xFF &&
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600384 (mc == SLIM_MSG_MC_CONNECT_SOURCE ||
385 mc == SLIM_MSG_MC_CONNECT_SINK ||
386 mc == SLIM_MSG_MC_DISCONNECT_PORT))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700387 la = dev->pgdla;
388 if (txn->dt == SLIM_MSG_DEST_LOGICALADDR)
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600389 *pbuf = SLIM_MSG_ASM_FIRST_WORD(txn->rl, txn->mt, mc, 0, la);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700390 else
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600391 *pbuf = SLIM_MSG_ASM_FIRST_WORD(txn->rl, txn->mt, mc, 1, la);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700392 if (txn->dt == SLIM_MSG_DEST_LOGICALADDR)
393 puc = ((u8 *)pbuf) + 3;
394 else
395 puc = ((u8 *)pbuf) + 2;
396 if (txn->rbuf)
397 *(puc++) = txn->tid;
398 if ((txn->mt == SLIM_MSG_MT_CORE) &&
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600399 ((mc >= SLIM_MSG_MC_REQUEST_INFORMATION &&
400 mc <= SLIM_MSG_MC_REPORT_INFORMATION) ||
401 (mc >= SLIM_MSG_MC_REQUEST_VALUE &&
402 mc <= SLIM_MSG_MC_CHANGE_VALUE))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700403 *(puc++) = (txn->ec & 0xFF);
404 *(puc++) = (txn->ec >> 8)&0xFF;
405 }
406 if (txn->wbuf)
407 memcpy(puc, txn->wbuf, txn->len);
408 if (txn->mt == SLIM_MSG_MT_CORE && txn->la == 0xFF &&
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600409 (mc == SLIM_MSG_MC_CONNECT_SOURCE ||
410 mc == SLIM_MSG_MC_CONNECT_SINK ||
411 mc == SLIM_MSG_MC_DISCONNECT_PORT)) {
412 if (mc != SLIM_MSG_MC_DISCONNECT_PORT)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700413 dev->err = msm_slim_connect_pipe_port(dev, *puc);
414 else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700415 /*
416 * Remove channel disconnects master-side ports from
417 * channel. No need to send that again on the bus
Sagar Dharia2d74c142013-05-17 02:24:06 -0600418 * Only disable port
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700419 */
Sagar Dharia2d74c142013-05-17 02:24:06 -0600420 writel_relaxed(0, PGD_PORT(PGD_PORT_CFGn,
421 (*puc + dev->port_b), dev->ver));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700422 mutex_unlock(&dev->tx_lock);
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700423 if (msgv >= 0)
424 msm_slim_put_ctrl(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700425 return 0;
426 }
427 if (dev->err) {
428 dev_err(dev->dev, "pipe-port connect err:%d", dev->err);
429 mutex_unlock(&dev->tx_lock);
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700430 if (msgv >= 0)
431 msm_slim_put_ctrl(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700432 return dev->err;
433 }
Sagar Dharia2b8a4b52013-05-15 20:01:45 -0600434 *(puc) = *(puc) + dev->port_b;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700435 }
436 if (txn->mt == SLIM_MSG_MT_CORE &&
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600437 mc == SLIM_MSG_MC_BEGIN_RECONFIGURATION)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700438 dev->reconf_busy = true;
Sagar Dharia2754ab42012-08-21 18:07:39 -0600439 msm_send_msg_buf(dev, pbuf, txn->rl, MGR_TX_MSG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700440 timeout = wait_for_completion_timeout(&done, HZ);
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700441 if (mc == SLIM_MSG_MC_RECONFIGURE_NOW) {
442 if ((txn->mc == (SLIM_MSG_MC_RECONFIGURE_NOW |
443 SLIM_MSG_CLK_PAUSE_SEQ_FLG)) &&
444 timeout) {
445 timeout = wait_for_completion_timeout(&dev->reconf, HZ);
446 dev->reconf_busy = false;
447 if (timeout) {
Sagar Dharia9acf7f42012-03-08 09:45:30 -0700448 clk_disable_unprepare(dev->rclk);
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700449 disable_irq(dev->irq);
450 }
451 }
452 if ((txn->mc == (SLIM_MSG_MC_RECONFIGURE_NOW |
453 SLIM_MSG_CLK_PAUSE_SEQ_FLG)) &&
454 !timeout) {
455 dev->reconf_busy = false;
456 dev_err(dev->dev, "clock pause failed");
457 mutex_unlock(&dev->tx_lock);
458 return -ETIMEDOUT;
459 }
460 if (txn->mt == SLIM_MSG_MT_CORE &&
461 txn->mc == SLIM_MSG_MC_RECONFIGURE_NOW) {
462 if (dev->ctrl.sched.usedslots == 0 &&
463 dev->chan_active) {
464 dev->chan_active = false;
465 msm_slim_put_ctrl(dev);
466 }
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600467 }
468 }
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600469 mutex_unlock(&dev->tx_lock);
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700470 if (msgv >= 0)
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600471 msm_slim_put_ctrl(dev);
472
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700473 if (!timeout)
474 dev_err(dev->dev, "TX timed out:MC:0x%x,mt:0x%x", txn->mc,
475 txn->mt);
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600476
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700477 return timeout ? dev->err : -ETIMEDOUT;
478}
479
Sagar Dhariaac913452012-09-04 11:27:26 -0600480static void msm_slim_wait_retry(struct msm_slim_ctrl *dev)
481{
482 int msec_per_frm = 0;
483 int sfr_per_sec;
484 /* Wait for 1 superframe, or default time and then retry */
485 sfr_per_sec = dev->framer.superfreq /
486 (1 << (SLIM_MAX_CLK_GEAR - dev->ctrl.clkgear));
487 if (sfr_per_sec)
488 msec_per_frm = MSEC_PER_SEC / sfr_per_sec;
489 if (msec_per_frm < DEF_RETRY_MS)
490 msec_per_frm = DEF_RETRY_MS;
491 msleep(msec_per_frm);
492}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700493static int msm_set_laddr(struct slim_controller *ctrl, const u8 *ea,
494 u8 elen, u8 laddr)
495{
496 struct msm_slim_ctrl *dev = slim_get_ctrldata(ctrl);
Sagar Dhariaac913452012-09-04 11:27:26 -0600497 struct completion done;
498 int timeout, ret, retries = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700499 u32 *buf;
Sagar Dhariaac913452012-09-04 11:27:26 -0600500retry_laddr:
501 init_completion(&done);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700502 mutex_lock(&dev->tx_lock);
Sagar Dharia8554f152014-04-01 15:36:15 -0600503 buf = msm_get_msg_buf(dev, 9, &done);
504 if (buf == NULL)
505 return -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700506 buf[0] = SLIM_MSG_ASM_FIRST_WORD(9, SLIM_MSG_MT_CORE,
507 SLIM_MSG_MC_ASSIGN_LOGICAL_ADDRESS,
508 SLIM_MSG_DEST_LOGICALADDR,
509 ea[5] | ea[4] << 8);
510 buf[1] = ea[3] | (ea[2] << 8) | (ea[1] << 16) | (ea[0] << 24);
511 buf[2] = laddr;
512
Sagar Dharia2754ab42012-08-21 18:07:39 -0600513 ret = msm_send_msg_buf(dev, buf, 9, MGR_TX_MSG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700514 timeout = wait_for_completion_timeout(&done, HZ);
Sagar Dhariaac913452012-09-04 11:27:26 -0600515 if (!timeout)
516 dev->err = -ETIMEDOUT;
517 if (dev->err) {
518 ret = dev->err;
519 dev->err = 0;
Sagar Dhariaac913452012-09-04 11:27:26 -0600520 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700521 mutex_unlock(&dev->tx_lock);
Sagar Dhariaac913452012-09-04 11:27:26 -0600522 if (ret) {
523 pr_err("set LADDR:0x%x failed:ret:%d, retrying", laddr, ret);
524 if (retries < INIT_MX_RETRIES) {
525 msm_slim_wait_retry(dev);
526 retries++;
527 goto retry_laddr;
528 } else {
529 pr_err("set LADDR failed after retrying:ret:%d", ret);
530 }
531 }
532 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700533}
534
Sagar Dharia144e5e02011-08-08 17:30:11 -0600535static int msm_clk_pause_wakeup(struct slim_controller *ctrl)
536{
537 struct msm_slim_ctrl *dev = slim_get_ctrldata(ctrl);
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600538 enable_irq(dev->irq);
Sagar Dharia9acf7f42012-03-08 09:45:30 -0700539 clk_prepare_enable(dev->rclk);
Sagar Dharia144e5e02011-08-08 17:30:11 -0600540 writel_relaxed(1, dev->base + FRM_WAKEUP);
541 /* Make sure framer wakeup write goes through before exiting function */
542 mb();
543 /*
544 * Workaround: Currently, slave is reporting lost-sync messages
545 * after slimbus comes out of clock pause.
546 * Transaction with slave fail before slave reports that message
547 * Give some time for that report to come
548 * Slimbus wakes up in clock gear 10 at 24.576MHz. With each superframe
549 * being 250 usecs, we wait for 20 superframes here to ensure
550 * we get the message
551 */
552 usleep_range(5000, 5000);
553 return 0;
554}
555
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700556static int msm_sat_define_ch(struct msm_slim_sat *sat, u8 *buf, u8 len, u8 mc)
557{
558 struct msm_slim_ctrl *dev = sat->dev;
559 enum slim_ch_control oper;
560 int i;
561 int ret = 0;
562 if (mc == SLIM_USR_MC_CHAN_CTRL) {
Sagar Dharia0ffdca12011-09-25 18:55:53 -0600563 for (i = 0; i < sat->nsatch; i++) {
564 if (buf[5] == sat->satch[i].chan)
565 break;
566 }
567 if (i >= sat->nsatch)
568 return -ENOTCONN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700569 oper = ((buf[3] & 0xC0) >> 6);
570 /* part of grp. activating/removing 1 will take care of rest */
Sagar Dharia0ffdca12011-09-25 18:55:53 -0600571 ret = slim_control_ch(&sat->satcl, sat->satch[i].chanh, oper,
572 false);
573 if (!ret) {
574 for (i = 5; i < len; i++) {
575 int j;
576 for (j = 0; j < sat->nsatch; j++) {
577 if (buf[i] == sat->satch[j].chan) {
578 if (oper == SLIM_CH_REMOVE)
579 sat->satch[j].req_rem++;
580 else
581 sat->satch[j].req_def++;
582 break;
583 }
584 }
585 }
586 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700587 } else {
588 u16 chh[40];
589 struct slim_ch prop;
590 u32 exp;
Sagar Dhariab886e042012-10-17 22:41:57 -0600591 u16 *grph = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700592 u8 coeff, cc;
593 u8 prrate = buf[6];
Sagar Dharia0ffdca12011-09-25 18:55:53 -0600594 if (len <= 8)
595 return -EINVAL;
596 for (i = 8; i < len; i++) {
597 int j = 0;
598 for (j = 0; j < sat->nsatch; j++) {
599 if (sat->satch[j].chan == buf[i]) {
600 chh[i - 8] = sat->satch[j].chanh;
601 break;
602 }
603 }
604 if (j < sat->nsatch) {
605 u16 dummy;
606 ret = slim_query_ch(&sat->satcl, buf[i],
607 &dummy);
608 if (ret)
609 return ret;
610 if (mc == SLIM_USR_MC_DEF_ACT_CHAN)
611 sat->satch[j].req_def++;
Sagar Dhariab886e042012-10-17 22:41:57 -0600612 /* First channel in group from satellite */
613 if (i == 8)
614 grph = &sat->satch[j].chanh;
Sagar Dharia0ffdca12011-09-25 18:55:53 -0600615 continue;
616 }
617 if (sat->nsatch >= MSM_MAX_SATCH)
618 return -EXFULL;
619 ret = slim_query_ch(&sat->satcl, buf[i], &chh[i - 8]);
620 if (ret)
621 return ret;
622 sat->satch[j].chan = buf[i];
623 sat->satch[j].chanh = chh[i - 8];
624 if (mc == SLIM_USR_MC_DEF_ACT_CHAN)
625 sat->satch[j].req_def++;
Sagar Dhariab886e042012-10-17 22:41:57 -0600626 if (i == 8)
627 grph = &sat->satch[j].chanh;
Sagar Dharia0ffdca12011-09-25 18:55:53 -0600628 sat->nsatch++;
629 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700630 prop.dataf = (enum slim_ch_dataf)((buf[3] & 0xE0) >> 5);
631 prop.auxf = (enum slim_ch_auxf)((buf[4] & 0xC0) >> 5);
632 prop.baser = SLIM_RATE_4000HZ;
633 if (prrate & 0x8)
634 prop.baser = SLIM_RATE_11025HZ;
635 else
636 prop.baser = SLIM_RATE_4000HZ;
637 prop.prot = (enum slim_ch_proto)(buf[5] & 0x0F);
638 prop.sampleszbits = (buf[4] & 0x1F)*SLIM_CL_PER_SL;
639 exp = (u32)((buf[5] & 0xF0) >> 4);
640 coeff = (buf[4] & 0x20) >> 5;
641 cc = (coeff ? 3 : 1);
642 prop.ratem = cc * (1 << exp);
643 if (i > 9)
644 ret = slim_define_ch(&sat->satcl, &prop, chh, len - 8,
Sagar Dharia0ffdca12011-09-25 18:55:53 -0600645 true, &chh[0]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700646 else
647 ret = slim_define_ch(&sat->satcl, &prop,
Sagar Dhariab886e042012-10-17 22:41:57 -0600648 chh, 1, true, &chh[0]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700649 dev_dbg(dev->dev, "define sat grp returned:%d", ret);
Sagar Dharia0ffdca12011-09-25 18:55:53 -0600650 if (ret)
651 return ret;
Sagar Dhariab886e042012-10-17 22:41:57 -0600652 else if (grph)
653 *grph = chh[0];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700654
655 /* part of group so activating 1 will take care of rest */
656 if (mc == SLIM_USR_MC_DEF_ACT_CHAN)
657 ret = slim_control_ch(&sat->satcl,
Sagar Dharia0ffdca12011-09-25 18:55:53 -0600658 chh[0],
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700659 SLIM_CH_ACTIVATE, false);
660 }
661 return ret;
662}
663
664static void msm_slim_rxwq(struct msm_slim_ctrl *dev)
665{
666 u8 buf[40];
667 u8 mc, mt, len;
668 int i, ret;
669 if ((msm_slim_rx_dequeue(dev, (u8 *)buf)) != -ENODATA) {
670 len = buf[0] & 0x1F;
671 mt = (buf[0] >> 5) & 0x7;
672 mc = buf[1];
673 if (mt == SLIM_MSG_MT_CORE &&
674 mc == SLIM_MSG_MC_REPORT_PRESENT) {
675 u8 laddr;
676 u8 e_addr[6];
677 for (i = 0; i < 6; i++)
678 e_addr[i] = buf[7-i];
679
Sagar Dhariaf0b9c752012-09-09 17:32:46 -0600680 ret = slim_assign_laddr(&dev->ctrl, e_addr, 6, &laddr,
681 false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700682 /* Is this Qualcomm ported generic device? */
683 if (!ret && e_addr[5] == QC_MFGID_LSB &&
684 e_addr[4] == QC_MFGID_MSB &&
685 e_addr[1] == QC_DEVID_PGD &&
686 e_addr[2] != QC_CHIPID_SL)
687 dev->pgdla = laddr;
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600688 if (!ret && !pm_runtime_enabled(dev->dev) &&
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700689 laddr == (QC_MSM_DEVS - 1))
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600690 pm_runtime_enable(dev->dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700691
Sagar Dharia790cfd02011-09-25 17:56:24 -0600692 if (!ret && msm_is_sat_dev(e_addr)) {
693 struct msm_slim_sat *sat = addr_to_sat(dev,
694 laddr);
695 if (!sat)
696 sat = msm_slim_alloc_sat(dev);
697 if (!sat)
698 return;
699
700 sat->satcl.laddr = laddr;
701 msm_sat_enqueue(sat, (u32 *)buf, len);
702 queue_work(sat->wq, &sat->wd);
703 }
Sagar Dhariaac913452012-09-04 11:27:26 -0600704 if (ret)
705 pr_err("assign laddr failed, error:%d", ret);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700706 } else if (mc == SLIM_MSG_MC_REPLY_INFORMATION ||
707 mc == SLIM_MSG_MC_REPLY_VALUE) {
708 u8 tid = buf[3];
709 dev_dbg(dev->dev, "tid:%d, len:%d\n", tid, len - 4);
710 slim_msg_response(&dev->ctrl, &buf[4], tid,
711 len - 4);
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700712 pm_runtime_mark_last_busy(dev->dev);
Sagar Dharia144e5e02011-08-08 17:30:11 -0600713 } else if (mc == SLIM_MSG_MC_REPORT_INFORMATION) {
714 u8 l_addr = buf[2];
715 u16 ele = (u16)buf[4] << 4;
716 ele |= ((buf[3] & 0xf0) >> 4);
717 dev_err(dev->dev, "Slim-dev:%d report inf element:0x%x",
718 l_addr, ele);
719 for (i = 0; i < len - 5; i++)
720 dev_err(dev->dev, "offset:0x%x:bit mask:%x",
721 i, buf[i+5]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700722 } else {
723 dev_err(dev->dev, "unexpected message:mc:%x, mt:%x",
724 mc, mt);
725 for (i = 0; i < len; i++)
726 dev_err(dev->dev, "error msg: %x", buf[i]);
727
728 }
729 } else
730 dev_err(dev->dev, "rxwq called and no dequeue");
731}
732
733static void slim_sat_rxprocess(struct work_struct *work)
734{
735 struct msm_slim_sat *sat = container_of(work, struct msm_slim_sat, wd);
736 struct msm_slim_ctrl *dev = sat->dev;
737 u8 buf[40];
738
739 while ((msm_sat_dequeue(sat, buf)) != -ENODATA) {
740 struct slim_msg_txn txn;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700741 u8 len, mc, mt;
742 u32 bw_sl;
743 int ret = 0;
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700744 int satv = -1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700745 bool gen_ack = false;
746 u8 tid;
747 u8 wbuf[8];
Sagar Dhariaac913452012-09-04 11:27:26 -0600748 int i, retries = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700749 txn.mt = SLIM_MSG_MT_SRC_REFERRED_USER;
750 txn.dt = SLIM_MSG_DEST_LOGICALADDR;
751 txn.ec = 0;
752 txn.rbuf = NULL;
753 txn.la = sat->satcl.laddr;
754 /* satellite handling */
755 len = buf[0] & 0x1F;
756 mc = buf[1];
757 mt = (buf[0] >> 5) & 0x7;
758
759 if (mt == SLIM_MSG_MT_CORE &&
760 mc == SLIM_MSG_MC_REPORT_PRESENT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700761 u8 e_addr[6];
762 for (i = 0; i < 6; i++)
763 e_addr[i] = buf[7-i];
764
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600765 if (pm_runtime_enabled(dev->dev)) {
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700766 satv = msm_slim_get_ctrl(dev);
767 if (satv >= 0)
768 sat->pending_capability = true;
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600769 }
Sagar Dharia69bf5572012-02-21 14:45:35 -0700770 /*
771 * Since capability message is already sent, present
772 * message will indicate subsystem hosting this
773 * satellite has restarted.
774 * Remove all active channels of this satellite
775 * when this is detected
776 */
777 if (sat->sent_capability) {
778 for (i = 0; i < sat->nsatch; i++) {
Sagar Dharia1944a132012-08-15 00:01:57 -0600779 if (sat->satch[i].reconf) {
780 pr_err("SSR, sat:%d, rm ch:%d",
Sagar Dhariaac913452012-09-04 11:27:26 -0600781 sat->satcl.laddr,
Sagar Dharia69bf5572012-02-21 14:45:35 -0700782 sat->satch[i].chan);
Sagar Dharia69bf5572012-02-21 14:45:35 -0700783 slim_control_ch(&sat->satcl,
784 sat->satch[i].chanh,
785 SLIM_CH_REMOVE, true);
Sagar Dhariab886e042012-10-17 22:41:57 -0600786 slim_dealloc_ch(&sat->satcl,
787 sat->satch[i].chanh);
Sagar Dharia1944a132012-08-15 00:01:57 -0600788 sat->satch[i].reconf = false;
789 }
Sagar Dharia69bf5572012-02-21 14:45:35 -0700790 }
791 }
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600792 } else if (mt != SLIM_MSG_MT_CORE &&
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700793 mc != SLIM_MSG_MC_REPORT_PRESENT) {
794 satv = msm_slim_get_ctrl(dev);
795 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700796 switch (mc) {
797 case SLIM_MSG_MC_REPORT_PRESENT:
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600798 /* Remove runtime_pm vote once satellite acks */
799 if (mt != SLIM_MSG_MT_CORE) {
800 if (pm_runtime_enabled(dev->dev) &&
801 sat->pending_capability) {
802 msm_slim_put_ctrl(dev);
803 sat->pending_capability = false;
804 }
805 continue;
806 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700807 /* send a Manager capability msg */
Sagar Dharia790cfd02011-09-25 17:56:24 -0600808 if (sat->sent_capability) {
809 if (mt == SLIM_MSG_MT_CORE)
810 goto send_capability;
811 else
812 continue;
813 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700814 ret = slim_add_device(&dev->ctrl, &sat->satcl);
815 if (ret) {
816 dev_err(dev->dev,
817 "Satellite-init failed");
818 continue;
819 }
Sagar Dharia0ffdca12011-09-25 18:55:53 -0600820 /* Satellite-channels */
821 sat->satch = kzalloc(MSM_MAX_SATCH *
822 sizeof(struct msm_sat_chan),
823 GFP_KERNEL);
Sagar Dharia790cfd02011-09-25 17:56:24 -0600824send_capability:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700825 txn.mc = SLIM_USR_MC_MASTER_CAPABILITY;
826 txn.mt = SLIM_MSG_MT_SRC_REFERRED_USER;
827 txn.la = sat->satcl.laddr;
828 txn.rl = 8;
829 wbuf[0] = SAT_MAGIC_LSB;
830 wbuf[1] = SAT_MAGIC_MSB;
831 wbuf[2] = SAT_MSG_VER;
832 wbuf[3] = SAT_MSG_PROT;
833 txn.wbuf = wbuf;
834 txn.len = 4;
Sagar Dhariaac913452012-09-04 11:27:26 -0600835 ret = msm_xfer_msg(&dev->ctrl, &txn);
836 if (ret) {
837 pr_err("capability for:0x%x fail:%d, retry:%d",
838 sat->satcl.laddr, ret, retries);
839 if (retries < INIT_MX_RETRIES) {
840 msm_slim_wait_retry(dev);
841 retries++;
842 goto send_capability;
843 } else {
844 pr_err("failed after all retries:%d",
845 ret);
846 }
847 } else {
848 sat->sent_capability = true;
849 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700850 break;
851 case SLIM_USR_MC_ADDR_QUERY:
852 memcpy(&wbuf[1], &buf[4], 6);
853 ret = slim_get_logical_addr(&sat->satcl,
854 &wbuf[1], 6, &wbuf[7]);
855 if (ret)
856 memset(&wbuf[1], 0, 6);
857 wbuf[0] = buf[3];
858 txn.mc = SLIM_USR_MC_ADDR_REPLY;
859 txn.rl = 12;
860 txn.len = 8;
861 txn.wbuf = wbuf;
862 msm_xfer_msg(&dev->ctrl, &txn);
863 break;
864 case SLIM_USR_MC_DEFINE_CHAN:
865 case SLIM_USR_MC_DEF_ACT_CHAN:
866 case SLIM_USR_MC_CHAN_CTRL:
867 if (mc != SLIM_USR_MC_CHAN_CTRL)
868 tid = buf[7];
869 else
870 tid = buf[4];
871 gen_ack = true;
872 ret = msm_sat_define_ch(sat, buf, len, mc);
873 if (ret) {
874 dev_err(dev->dev,
875 "SAT define_ch returned:%d",
876 ret);
877 }
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600878 if (!sat->pending_reconf) {
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700879 int chv = msm_slim_get_ctrl(dev);
880 if (chv >= 0)
881 sat->pending_reconf = true;
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600882 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700883 break;
884 case SLIM_USR_MC_RECONFIG_NOW:
885 tid = buf[3];
886 gen_ack = true;
887 ret = slim_reconfigure_now(&sat->satcl);
Sagar Dharia0ffdca12011-09-25 18:55:53 -0600888 for (i = 0; i < sat->nsatch; i++) {
889 struct msm_sat_chan *sch = &sat->satch[i];
Sagar Dhariaef444892012-09-05 12:19:24 -0600890 if (sch->req_rem && sch->reconf) {
Sagar Dharia1944a132012-08-15 00:01:57 -0600891 if (!ret) {
Sagar Dharia0ffdca12011-09-25 18:55:53 -0600892 slim_dealloc_ch(&sat->satcl,
893 sch->chanh);
Sagar Dharia1944a132012-08-15 00:01:57 -0600894 sch->reconf = false;
895 }
Sagar Dharia0ffdca12011-09-25 18:55:53 -0600896 sch->req_rem--;
897 } else if (sch->req_def) {
898 if (ret)
899 slim_dealloc_ch(&sat->satcl,
900 sch->chanh);
Sagar Dharia1944a132012-08-15 00:01:57 -0600901 else
902 sch->reconf = true;
Sagar Dharia0ffdca12011-09-25 18:55:53 -0600903 sch->req_def--;
904 }
905 }
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600906 if (sat->pending_reconf) {
907 msm_slim_put_ctrl(dev);
908 sat->pending_reconf = false;
909 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700910 break;
911 case SLIM_USR_MC_REQ_BW:
912 /* what we get is in SLOTS */
913 bw_sl = (u32)buf[4] << 3 |
914 ((buf[3] & 0xE0) >> 5);
915 sat->satcl.pending_msgsl = bw_sl;
916 tid = buf[5];
917 gen_ack = true;
918 break;
919 case SLIM_USR_MC_CONNECT_SRC:
920 case SLIM_USR_MC_CONNECT_SINK:
921 if (mc == SLIM_USR_MC_CONNECT_SRC)
922 txn.mc = SLIM_MSG_MC_CONNECT_SOURCE;
923 else
924 txn.mc = SLIM_MSG_MC_CONNECT_SINK;
925 wbuf[0] = buf[4] & 0x1F;
926 wbuf[1] = buf[5];
927 tid = buf[6];
928 txn.la = buf[3];
929 txn.mt = SLIM_MSG_MT_CORE;
930 txn.rl = 6;
931 txn.len = 2;
932 txn.wbuf = wbuf;
933 gen_ack = true;
934 ret = msm_xfer_msg(&dev->ctrl, &txn);
935 break;
936 case SLIM_USR_MC_DISCONNECT_PORT:
937 txn.mc = SLIM_MSG_MC_DISCONNECT_PORT;
938 wbuf[0] = buf[4] & 0x1F;
939 tid = buf[5];
940 txn.la = buf[3];
941 txn.rl = 5;
942 txn.len = 1;
943 txn.mt = SLIM_MSG_MT_CORE;
944 txn.wbuf = wbuf;
945 gen_ack = true;
946 ret = msm_xfer_msg(&dev->ctrl, &txn);
Kiran Gunda33a23a92013-01-10 17:03:33 +0530947 break;
948 case SLIM_MSG_MC_REPORT_ABSENT:
949 dev_info(dev->dev, "Received Report Absent Message\n");
950 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700951 default:
952 break;
953 }
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600954 if (!gen_ack) {
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700955 if (mc != SLIM_MSG_MC_REPORT_PRESENT && satv >= 0)
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600956 msm_slim_put_ctrl(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700957 continue;
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600958 }
959
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700960 wbuf[0] = tid;
961 if (!ret)
962 wbuf[1] = MSM_SAT_SUCCSS;
963 else
964 wbuf[1] = 0;
965 txn.mc = SLIM_USR_MC_GENERIC_ACK;
966 txn.la = sat->satcl.laddr;
967 txn.rl = 6;
968 txn.len = 2;
969 txn.wbuf = wbuf;
970 txn.mt = SLIM_MSG_MT_SRC_REFERRED_USER;
971 msm_xfer_msg(&dev->ctrl, &txn);
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700972 if (satv >= 0)
973 msm_slim_put_ctrl(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700974 }
975}
976
Sagar Dharia790cfd02011-09-25 17:56:24 -0600977static struct msm_slim_sat *msm_slim_alloc_sat(struct msm_slim_ctrl *dev)
978{
979 struct msm_slim_sat *sat;
980 char *name;
981 if (dev->nsats >= MSM_MAX_NSATS)
982 return NULL;
983
984 sat = kzalloc(sizeof(struct msm_slim_sat), GFP_KERNEL);
985 if (!sat) {
986 dev_err(dev->dev, "no memory for satellite");
987 return NULL;
988 }
989 name = kzalloc(SLIMBUS_NAME_SIZE, GFP_KERNEL);
990 if (!name) {
991 dev_err(dev->dev, "no memory for satellite name");
992 kfree(sat);
993 return NULL;
994 }
995 dev->satd[dev->nsats] = sat;
996 sat->dev = dev;
997 snprintf(name, SLIMBUS_NAME_SIZE, "msm_sat%d", dev->nsats);
998 sat->satcl.name = name;
999 spin_lock_init(&sat->lock);
1000 INIT_WORK(&sat->wd, slim_sat_rxprocess);
1001 sat->wq = create_singlethread_workqueue(sat->satcl.name);
1002 if (!sat->wq) {
1003 kfree(name);
1004 kfree(sat);
1005 return NULL;
1006 }
1007 /*
1008 * Both sats will be allocated from RX thread and RX thread will
1009 * process messages sequentially. No synchronization necessary
1010 */
1011 dev->nsats++;
1012 return sat;
1013}
1014
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001015static int msm_slim_rx_msgq_thread(void *data)
1016{
1017 struct msm_slim_ctrl *dev = (struct msm_slim_ctrl *)data;
1018 struct completion *notify = &dev->rx_msgq_notify;
1019 struct msm_slim_sat *sat = NULL;
1020 u32 mc = 0;
1021 u32 mt = 0;
1022 u32 buffer[10];
1023 int index = 0;
1024 u8 msg_len = 0;
1025 int ret;
1026
1027 dev_dbg(dev->dev, "rx thread started");
1028
1029 while (!kthread_should_stop()) {
1030 set_current_state(TASK_INTERRUPTIBLE);
1031 ret = wait_for_completion_interruptible(notify);
1032
1033 if (ret)
1034 dev_err(dev->dev, "rx thread wait error:%d", ret);
1035
1036 /* 1 irq notification per message */
Sagar Dharia24419e32013-01-14 17:56:32 -07001037 if (dev->use_rx_msgqs != MSM_MSGQ_ENABLED) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001038 msm_slim_rxwq(dev);
1039 continue;
1040 }
1041
1042 ret = msm_slim_rx_msgq_get(dev, buffer, index);
1043 if (ret) {
1044 dev_err(dev->dev, "rx_msgq_get() failed 0x%x\n", ret);
1045 continue;
1046 }
1047
1048 pr_debug("message[%d] = 0x%x\n", index, *buffer);
1049
1050 /* Decide if we use generic RX or satellite RX */
1051 if (index++ == 0) {
1052 msg_len = *buffer & 0x1F;
1053 pr_debug("Start of new message, len = %d\n", msg_len);
1054 mt = (buffer[0] >> 5) & 0x7;
1055 mc = (buffer[0] >> 8) & 0xff;
1056 dev_dbg(dev->dev, "MC: %x, MT: %x\n", mc, mt);
1057 if (mt == SLIM_MSG_MT_DEST_REFERRED_USER ||
Sagar Dharia790cfd02011-09-25 17:56:24 -06001058 mt == SLIM_MSG_MT_SRC_REFERRED_USER) {
1059 u8 laddr;
1060 laddr = (u8)((buffer[0] >> 16) & 0xff);
1061 sat = addr_to_sat(dev, laddr);
1062 }
Kiran Gunda33a23a92013-01-10 17:03:33 +05301063 }
1064 if ((index * 4) >= msg_len) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001065 index = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001066 if (sat) {
1067 msm_sat_enqueue(sat, buffer, msg_len);
1068 queue_work(sat->wq, &sat->wd);
1069 sat = NULL;
1070 } else {
1071 msm_slim_rx_enqueue(dev, buffer, msg_len);
1072 msm_slim_rxwq(dev);
1073 }
1074 }
1075 }
1076
1077 return 0;
1078}
1079
Sagar Dhariacc969452011-09-19 10:34:30 -06001080static void msm_slim_prg_slew(struct platform_device *pdev,
1081 struct msm_slim_ctrl *dev)
1082{
1083 struct resource *slew_io;
1084 void __iomem *slew_reg;
1085 /* SLEW RATE register for this slimbus */
1086 dev->slew_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
1087 "slimbus_slew_reg");
1088 if (!dev->slew_mem) {
1089 dev_dbg(&pdev->dev, "no slimbus slew resource\n");
1090 return;
1091 }
1092 slew_io = request_mem_region(dev->slew_mem->start,
1093 resource_size(dev->slew_mem), pdev->name);
1094 if (!slew_io) {
1095 dev_dbg(&pdev->dev, "slimbus-slew mem claimed\n");
1096 dev->slew_mem = NULL;
1097 return;
1098 }
1099
1100 slew_reg = ioremap(dev->slew_mem->start, resource_size(dev->slew_mem));
1101 if (!slew_reg) {
1102 dev_dbg(dev->dev, "slew register mapping failed");
1103 release_mem_region(dev->slew_mem->start,
1104 resource_size(dev->slew_mem));
1105 dev->slew_mem = NULL;
1106 return;
1107 }
1108 writel_relaxed(1, slew_reg);
1109 /* Make sure slimbus-slew rate enabling goes through */
1110 wmb();
1111 iounmap(slew_reg);
1112}
1113
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001114static int __devinit msm_slim_probe(struct platform_device *pdev)
1115{
1116 struct msm_slim_ctrl *dev;
1117 int ret;
Joonwoo Parkf69f77a2012-08-28 15:26:11 -07001118 enum apr_subsys_state q6_state;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001119 struct resource *bam_mem, *bam_io;
1120 struct resource *slim_mem, *slim_io;
1121 struct resource *irq, *bam_irq;
Sagar Dharia1beb2202012-07-31 19:06:21 -06001122 bool rxreg_access = false;
Joonwoo Parkf69f77a2012-08-28 15:26:11 -07001123
1124 q6_state = apr_get_q6_state();
1125 if (q6_state == APR_SUBSYS_DOWN) {
1126 dev_dbg(&pdev->dev, "defering %s, adsp_state %d\n", __func__,
1127 q6_state);
1128 return -EPROBE_DEFER;
1129 } else
1130 dev_dbg(&pdev->dev, "adsp is ready\n");
1131
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001132 slim_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
1133 "slimbus_physical");
1134 if (!slim_mem) {
1135 dev_err(&pdev->dev, "no slimbus physical memory resource\n");
1136 return -ENODEV;
1137 }
1138 slim_io = request_mem_region(slim_mem->start, resource_size(slim_mem),
1139 pdev->name);
1140 if (!slim_io) {
1141 dev_err(&pdev->dev, "slimbus memory already claimed\n");
1142 return -EBUSY;
1143 }
1144
1145 bam_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
1146 "slimbus_bam_physical");
1147 if (!bam_mem) {
1148 dev_err(&pdev->dev, "no slimbus BAM memory resource\n");
1149 ret = -ENODEV;
1150 goto err_get_res_bam_failed;
1151 }
1152 bam_io = request_mem_region(bam_mem->start, resource_size(bam_mem),
1153 pdev->name);
1154 if (!bam_io) {
1155 release_mem_region(slim_mem->start, resource_size(slim_mem));
1156 dev_err(&pdev->dev, "slimbus BAM memory already claimed\n");
1157 ret = -EBUSY;
1158 goto err_get_res_bam_failed;
1159 }
1160 irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
1161 "slimbus_irq");
1162 if (!irq) {
1163 dev_err(&pdev->dev, "no slimbus IRQ resource\n");
1164 ret = -ENODEV;
1165 goto err_get_res_failed;
1166 }
1167 bam_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
1168 "slimbus_bam_irq");
1169 if (!bam_irq) {
1170 dev_err(&pdev->dev, "no slimbus BAM IRQ resource\n");
1171 ret = -ENODEV;
1172 goto err_get_res_failed;
1173 }
1174
1175 dev = kzalloc(sizeof(struct msm_slim_ctrl), GFP_KERNEL);
1176 if (!dev) {
1177 dev_err(&pdev->dev, "no memory for MSM slimbus controller\n");
1178 ret = -ENOMEM;
1179 goto err_get_res_failed;
1180 }
Sagar Dharia8554f152014-04-01 15:36:15 -06001181 dev->wr_comp = kzalloc(sizeof(struct completion *) * MSM_TX_BUFS,
1182 GFP_KERNEL);
1183 if (!dev->wr_comp)
1184 return -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001185 dev->dev = &pdev->dev;
1186 platform_set_drvdata(pdev, dev);
1187 slim_set_ctrldata(&dev->ctrl, dev);
1188 dev->base = ioremap(slim_mem->start, resource_size(slim_mem));
1189 if (!dev->base) {
1190 dev_err(&pdev->dev, "IOremap failed\n");
1191 ret = -ENOMEM;
1192 goto err_ioremap_failed;
1193 }
1194 dev->bam.base = ioremap(bam_mem->start, resource_size(bam_mem));
1195 if (!dev->bam.base) {
1196 dev_err(&pdev->dev, "BAM IOremap failed\n");
1197 ret = -ENOMEM;
1198 goto err_ioremap_bam_failed;
1199 }
Sagar Dhariaf8f603b2012-03-21 15:25:17 -06001200 if (pdev->dev.of_node) {
1201
1202 ret = of_property_read_u32(pdev->dev.of_node, "cell-index",
1203 &dev->ctrl.nr);
1204 if (ret) {
1205 dev_err(&pdev->dev, "Cell index not specified:%d", ret);
1206 goto err_of_init_failed;
1207 }
Sagar Dharia1beb2202012-07-31 19:06:21 -06001208 rxreg_access = of_property_read_bool(pdev->dev.of_node,
1209 "qcom,rxreg-access");
Sagar Dhariaf8f603b2012-03-21 15:25:17 -06001210 /* Optional properties */
1211 ret = of_property_read_u32(pdev->dev.of_node,
1212 "qcom,min-clk-gear", &dev->ctrl.min_cg);
1213 ret = of_property_read_u32(pdev->dev.of_node,
1214 "qcom,max-clk-gear", &dev->ctrl.max_cg);
Sagar Dharia1beb2202012-07-31 19:06:21 -06001215 pr_debug("min_cg:%d, max_cg:%d, rxreg: %d", dev->ctrl.min_cg,
1216 dev->ctrl.max_cg, rxreg_access);
Sagar Dhariaf8f603b2012-03-21 15:25:17 -06001217 } else {
1218 dev->ctrl.nr = pdev->id;
1219 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001220 dev->ctrl.nchans = MSM_SLIM_NCHANS;
1221 dev->ctrl.nports = MSM_SLIM_NPORTS;
1222 dev->ctrl.set_laddr = msm_set_laddr;
1223 dev->ctrl.xfer_msg = msm_xfer_msg;
Sagar Dharia144e5e02011-08-08 17:30:11 -06001224 dev->ctrl.wakeup = msm_clk_pause_wakeup;
Sagar Dharia100e7212013-05-17 18:20:57 -06001225 dev->ctrl.alloc_port = msm_alloc_port;
1226 dev->ctrl.dealloc_port = msm_dealloc_port;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001227 dev->ctrl.port_xfer = msm_slim_port_xfer;
1228 dev->ctrl.port_xfer_status = msm_slim_port_xfer_status;
1229 /* Reserve some messaging BW for satellite-apps driver communication */
1230 dev->ctrl.sched.pending_msgsl = 30;
1231
1232 init_completion(&dev->reconf);
1233 mutex_init(&dev->tx_lock);
1234 spin_lock_init(&dev->rx_lock);
1235 dev->ee = 1;
Sagar Dharia1beb2202012-07-31 19:06:21 -06001236 if (rxreg_access)
Sagar Dharia24419e32013-01-14 17:56:32 -07001237 dev->use_rx_msgqs = MSM_MSGQ_DISABLED;
Sagar Dharia1beb2202012-07-31 19:06:21 -06001238 else
Sagar Dharia24419e32013-01-14 17:56:32 -07001239 dev->use_rx_msgqs = MSM_MSGQ_RESET;
Sagar Dharia1beb2202012-07-31 19:06:21 -06001240
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001241 dev->irq = irq->start;
1242 dev->bam.irq = bam_irq->start;
1243
Sagar Dhariadebc8b72012-08-11 15:02:12 -06001244 dev->hclk = clk_get(dev->dev, "iface_clk");
1245 if (IS_ERR(dev->hclk))
1246 dev->hclk = NULL;
1247 else
1248 clk_prepare_enable(dev->hclk);
1249
Sagar Dharia60f59a72012-10-17 12:42:03 -06001250 ret = msm_slim_sps_init(dev, bam_mem, MGR_STATUS, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001251 if (ret != 0) {
1252 dev_err(dev->dev, "error SPS init\n");
1253 goto err_sps_init_failed;
1254 }
1255
Sagar Dharia2754ab42012-08-21 18:07:39 -06001256 /* Fire up the Rx message queue thread */
1257 dev->rx_msgq_thread = kthread_run(msm_slim_rx_msgq_thread, dev,
1258 MSM_SLIM_NAME "_rx_msgq_thread");
1259 if (IS_ERR(dev->rx_msgq_thread)) {
1260 ret = PTR_ERR(dev->rx_msgq_thread);
1261 dev_err(dev->dev, "Failed to start Rx message queue thread\n");
1262 goto err_thread_create_failed;
1263 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001264
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001265 dev->framer.rootfreq = SLIM_ROOT_FREQ >> 3;
1266 dev->framer.superfreq =
1267 dev->framer.rootfreq / SLIM_CL_PER_SUPERFRAME_DIV8;
1268 dev->ctrl.a_framer = &dev->framer;
1269 dev->ctrl.clkgear = SLIM_MAX_CLK_GEAR;
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001270 dev->ctrl.dev.parent = &pdev->dev;
Sagar Dhariaf8f603b2012-03-21 15:25:17 -06001271 dev->ctrl.dev.of_node = pdev->dev.of_node;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001272
Sagar Dharia8554f152014-04-01 15:36:15 -06001273 ret = request_threaded_irq(dev->irq, NULL, msm_slim_interrupt,
1274 IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001275 "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:
Sagar Dharia8554f152014-04-01 15:36:15 -06001403 kfree(dev->wr_comp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001404 kfree(dev);
1405err_get_res_failed:
1406 release_mem_region(bam_mem->start, resource_size(bam_mem));
1407err_get_res_bam_failed:
1408 release_mem_region(slim_mem->start, resource_size(slim_mem));
1409 return ret;
1410}
1411
1412static int __devexit msm_slim_remove(struct platform_device *pdev)
1413{
1414 struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
1415 struct resource *bam_mem;
1416 struct resource *slim_mem;
Sagar Dhariacc969452011-09-19 10:34:30 -06001417 struct resource *slew_mem = dev->slew_mem;
Sagar Dharia790cfd02011-09-25 17:56:24 -06001418 int i;
1419 for (i = 0; i < dev->nsats; i++) {
1420 struct msm_slim_sat *sat = dev->satd[i];
Sagar Dharia0ffdca12011-09-25 18:55:53 -06001421 int j;
1422 for (j = 0; j < sat->nsatch; j++)
1423 slim_dealloc_ch(&sat->satcl, sat->satch[j].chanh);
Sagar Dharia790cfd02011-09-25 17:56:24 -06001424 slim_remove_device(&sat->satcl);
1425 kfree(sat->satch);
1426 destroy_workqueue(sat->wq);
1427 kfree(sat->satcl.name);
1428 kfree(sat);
1429 }
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001430 pm_runtime_disable(&pdev->dev);
1431 pm_runtime_set_suspended(&pdev->dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001432 free_irq(dev->irq, dev);
1433 slim_del_controller(&dev->ctrl);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001434 clk_put(dev->rclk);
Sagar Dhariadebc8b72012-08-11 15:02:12 -06001435 if (dev->hclk)
1436 clk_put(dev->hclk);
Sagar Dharia33beca02012-10-22 16:21:46 -06001437 msm_slim_sps_exit(dev, true);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001438 kthread_stop(dev->rx_msgq_thread);
1439 iounmap(dev->bam.base);
1440 iounmap(dev->base);
Sagar Dharia8554f152014-04-01 15:36:15 -06001441 kfree(dev->wr_comp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001442 kfree(dev);
1443 bam_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
1444 "slimbus_bam_physical");
Sagar Dhariae77961f2011-09-27 14:03:50 -06001445 if (bam_mem)
1446 release_mem_region(bam_mem->start, resource_size(bam_mem));
Sagar Dhariacc969452011-09-19 10:34:30 -06001447 if (slew_mem)
1448 release_mem_region(slew_mem->start, resource_size(slew_mem));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001449 slim_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
1450 "slimbus_physical");
Sagar Dhariae77961f2011-09-27 14:03:50 -06001451 if (slim_mem)
1452 release_mem_region(slim_mem->start, resource_size(slim_mem));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001453 return 0;
1454}
1455
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001456#ifdef CONFIG_PM_RUNTIME
1457static int msm_slim_runtime_idle(struct device *device)
1458{
Sagar Dhariad1468b72013-07-16 12:56:22 -06001459 struct platform_device *pdev = to_platform_device(device);
1460 struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
1461 if (dev->state == MSM_CTRL_AWAKE)
1462 dev->state = MSM_CTRL_IDLE;
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001463 dev_dbg(device, "pm_runtime: idle...\n");
1464 pm_request_autosuspend(device);
1465 return -EAGAIN;
1466}
1467#endif
1468
1469/*
1470 * If PM_RUNTIME is not defined, these 2 functions become helper
1471 * functions to be called from system suspend/resume. So they are not
1472 * inside ifdef CONFIG_PM_RUNTIME
1473 */
Sagar Dharia45e77912012-01-10 09:55:18 -07001474#ifdef CONFIG_PM_SLEEP
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001475static int msm_slim_runtime_suspend(struct device *device)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001476{
1477 struct platform_device *pdev = to_platform_device(device);
1478 struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001479 int ret;
1480 dev_dbg(device, "pm_runtime: suspending...\n");
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001481 ret = slim_ctrl_clk_pause(&dev->ctrl, false, SLIM_CLK_UNSPECIFIED);
Sagar Dhariad3ef30a2011-12-09 14:30:45 -07001482 if (ret) {
1483 dev_err(device, "clk pause not entered:%d", ret);
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001484 dev->state = MSM_CTRL_AWAKE;
Sagar Dhariad3ef30a2011-12-09 14:30:45 -07001485 } else {
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001486 dev->state = MSM_CTRL_ASLEEP;
Sagar Dhariad3ef30a2011-12-09 14:30:45 -07001487 }
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001488 return ret;
1489}
1490
1491static int msm_slim_runtime_resume(struct device *device)
1492{
1493 struct platform_device *pdev = to_platform_device(device);
1494 struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
1495 int ret = 0;
1496 dev_dbg(device, "pm_runtime: resuming...\n");
1497 if (dev->state == MSM_CTRL_ASLEEP)
1498 ret = slim_ctrl_clk_pause(&dev->ctrl, true, 0);
Sagar Dhariad3ef30a2011-12-09 14:30:45 -07001499 if (ret) {
1500 dev_err(device, "clk pause not exited:%d", ret);
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001501 dev->state = MSM_CTRL_ASLEEP;
Sagar Dhariad3ef30a2011-12-09 14:30:45 -07001502 } else {
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001503 dev->state = MSM_CTRL_AWAKE;
Sagar Dhariad3ef30a2011-12-09 14:30:45 -07001504 }
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001505 return ret;
1506}
1507
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001508static int msm_slim_suspend(struct device *dev)
1509{
Sagar Dhariad1468b72013-07-16 12:56:22 -06001510 int ret = -EBUSY;
1511 struct platform_device *pdev = to_platform_device(dev);
1512 struct msm_slim_ctrl *cdev = platform_get_drvdata(pdev);
1513 if (!pm_runtime_enabled(dev) ||
1514 (!pm_runtime_suspended(dev) &&
1515 cdev->state == MSM_CTRL_IDLE)) {
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001516 dev_dbg(dev, "system suspend");
1517 ret = msm_slim_runtime_suspend(dev);
Sagar Dhariadebc8b72012-08-11 15:02:12 -06001518 if (!ret) {
1519 if (cdev->hclk)
1520 clk_disable_unprepare(cdev->hclk);
1521 }
Sagar Dharia6b559e02011-08-03 17:01:31 -06001522 }
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001523 if (ret == -EBUSY) {
Sagar Dharia144e5e02011-08-08 17:30:11 -06001524 /*
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001525 * If the clock pause failed due to active channels, there is
1526 * a possibility that some audio stream is active during suspend
1527 * We dont want to return suspend failure in that case so that
1528 * display and relevant components can still go to suspend.
1529 * If there is some other error, then it should be passed-on
1530 * to system level suspend
1531 */
Sagar Dharia144e5e02011-08-08 17:30:11 -06001532 ret = 0;
1533 }
1534 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001535}
1536
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001537static int msm_slim_resume(struct device *dev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001538{
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001539 /* If runtime_pm is enabled, this resume shouldn't do anything */
1540 if (!pm_runtime_enabled(dev) || !pm_runtime_suspended(dev)) {
Sagar Dhariadebc8b72012-08-11 15:02:12 -06001541 struct platform_device *pdev = to_platform_device(dev);
1542 struct msm_slim_ctrl *cdev = platform_get_drvdata(pdev);
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001543 int ret;
1544 dev_dbg(dev, "system resume");
Sagar Dhariadebc8b72012-08-11 15:02:12 -06001545 if (cdev->hclk)
1546 clk_prepare_enable(cdev->hclk);
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001547 ret = msm_slim_runtime_resume(dev);
1548 if (!ret) {
1549 pm_runtime_mark_last_busy(dev);
1550 pm_request_autosuspend(dev);
1551 }
1552 return ret;
1553
Sagar Dharia144e5e02011-08-08 17:30:11 -06001554 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001555 return 0;
1556}
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001557#endif /* CONFIG_PM_SLEEP */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001558
1559static const struct dev_pm_ops msm_slim_dev_pm_ops = {
1560 SET_SYSTEM_SLEEP_PM_OPS(
1561 msm_slim_suspend,
1562 msm_slim_resume
1563 )
1564 SET_RUNTIME_PM_OPS(
1565 msm_slim_runtime_suspend,
1566 msm_slim_runtime_resume,
1567 msm_slim_runtime_idle
1568 )
1569};
1570
Sagar Dhariaf8f603b2012-03-21 15:25:17 -06001571static struct of_device_id msm_slim_dt_match[] = {
1572 {
1573 .compatible = "qcom,slim-msm",
1574 },
1575 {}
1576};
1577
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001578static struct platform_driver msm_slim_driver = {
1579 .probe = msm_slim_probe,
1580 .remove = msm_slim_remove,
1581 .driver = {
1582 .name = MSM_SLIM_NAME,
1583 .owner = THIS_MODULE,
1584 .pm = &msm_slim_dev_pm_ops,
Sagar Dhariaf8f603b2012-03-21 15:25:17 -06001585 .of_match_table = msm_slim_dt_match,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001586 },
1587};
1588
1589static int msm_slim_init(void)
1590{
1591 return platform_driver_register(&msm_slim_driver);
1592}
1593subsys_initcall(msm_slim_init);
1594
1595static void msm_slim_exit(void)
1596{
1597 platform_driver_unregister(&msm_slim_driver);
1598}
1599module_exit(msm_slim_exit);
1600
1601MODULE_LICENSE("GPL v2");
1602MODULE_VERSION("0.1");
1603MODULE_DESCRIPTION("MSM Slimbus controller");
1604MODULE_ALIAS("platform:msm-slim");