blob: 4a3ea76103f2094ac18d103b52f18c8066dbbbe4 [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
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070033#define QC_MFGID_LSB 0x2
34#define QC_MFGID_MSB 0x17
35#define QC_CHIPID_SL 0x10
36#define QC_DEVID_SAT1 0x3
37#define QC_DEVID_SAT2 0x4
38#define QC_DEVID_PGD 0x5
Sagar Dharia45ee38a2011-08-03 17:01:31 -060039#define QC_MSM_DEVS 5
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070040
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070041/* Manager registers */
42enum mgr_reg {
43 MGR_CFG = 0x200,
44 MGR_STATUS = 0x204,
45 MGR_RX_MSGQ_CFG = 0x208,
46 MGR_INT_EN = 0x210,
47 MGR_INT_STAT = 0x214,
48 MGR_INT_CLR = 0x218,
49 MGR_TX_MSG = 0x230,
50 MGR_RX_MSG = 0x270,
Sagar Dhariaac913452012-09-04 11:27:26 -060051 MGR_IE_STAT = 0x2F0,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070052 MGR_VE_STAT = 0x300,
53};
54
55enum msg_cfg {
56 MGR_CFG_ENABLE = 1,
57 MGR_CFG_RX_MSGQ_EN = 1 << 1,
58 MGR_CFG_TX_MSGQ_EN_HIGH = 1 << 2,
59 MGR_CFG_TX_MSGQ_EN_LOW = 1 << 3,
60};
61/* Message queue types */
62enum msm_slim_msgq_type {
63 MSGQ_RX = 0,
64 MSGQ_TX_LOW = 1,
65 MSGQ_TX_HIGH = 2,
66};
67/* Framer registers */
68enum frm_reg {
69 FRM_CFG = 0x400,
70 FRM_STAT = 0x404,
71 FRM_INT_EN = 0x410,
72 FRM_INT_STAT = 0x414,
73 FRM_INT_CLR = 0x418,
74 FRM_WAKEUP = 0x41C,
75 FRM_CLKCTL_DONE = 0x420,
76 FRM_IE_STAT = 0x430,
77 FRM_VE_STAT = 0x440,
78};
79
80/* Interface registers */
81enum intf_reg {
82 INTF_CFG = 0x600,
83 INTF_STAT = 0x604,
84 INTF_INT_EN = 0x610,
85 INTF_INT_STAT = 0x614,
86 INTF_INT_CLR = 0x618,
87 INTF_IE_STAT = 0x630,
88 INTF_VE_STAT = 0x640,
89};
90
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070091enum mgr_intr {
92 MGR_INT_RECFG_DONE = 1 << 24,
93 MGR_INT_TX_NACKED_2 = 1 << 25,
94 MGR_INT_MSG_BUF_CONTE = 1 << 26,
95 MGR_INT_RX_MSG_RCVD = 1 << 30,
96 MGR_INT_TX_MSG_SENT = 1 << 31,
97};
98
99enum frm_cfg {
100 FRM_ACTIVE = 1,
101 CLK_GEAR = 7,
102 ROOT_FREQ = 11,
103 REF_CLK_GEAR = 15,
Sagar Dhariadebc8b72012-08-11 15:02:12 -0600104 INTR_WAKE = 19,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700105};
106
Sagar Dharia790cfd02011-09-25 17:56:24 -0600107static struct msm_slim_sat *msm_slim_alloc_sat(struct msm_slim_ctrl *dev);
108
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700109static int msm_sat_enqueue(struct msm_slim_sat *sat, u32 *buf, u8 len)
110{
111 struct msm_slim_ctrl *dev = sat->dev;
Stephen Boyd3cdfc712012-10-31 17:41:43 -0700112 unsigned long flags;
113 spin_lock_irqsave(&sat->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700114 if ((sat->stail + 1) % SAT_CONCUR_MSG == sat->shead) {
Stephen Boyd3cdfc712012-10-31 17:41:43 -0700115 spin_unlock_irqrestore(&sat->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700116 dev_err(dev->dev, "SAT QUEUE full!");
117 return -EXFULL;
118 }
119 memcpy(sat->sat_msgs[sat->stail], (u8 *)buf, len);
120 sat->stail = (sat->stail + 1) % SAT_CONCUR_MSG;
Stephen Boyd3cdfc712012-10-31 17:41:43 -0700121 spin_unlock_irqrestore(&sat->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700122 return 0;
123}
124
125static int msm_sat_dequeue(struct msm_slim_sat *sat, u8 *buf)
126{
127 unsigned long flags;
128 spin_lock_irqsave(&sat->lock, flags);
129 if (sat->stail == sat->shead) {
130 spin_unlock_irqrestore(&sat->lock, flags);
131 return -ENODATA;
132 }
133 memcpy(buf, sat->sat_msgs[sat->shead], 40);
134 sat->shead = (sat->shead + 1) % SAT_CONCUR_MSG;
135 spin_unlock_irqrestore(&sat->lock, flags);
136 return 0;
137}
138
139static void msm_get_eaddr(u8 *e_addr, u32 *buffer)
140{
141 e_addr[0] = (buffer[1] >> 24) & 0xff;
142 e_addr[1] = (buffer[1] >> 16) & 0xff;
143 e_addr[2] = (buffer[1] >> 8) & 0xff;
144 e_addr[3] = buffer[1] & 0xff;
145 e_addr[4] = (buffer[0] >> 24) & 0xff;
146 e_addr[5] = (buffer[0] >> 16) & 0xff;
147}
148
149static bool msm_is_sat_dev(u8 *e_addr)
150{
151 if (e_addr[5] == QC_MFGID_LSB && e_addr[4] == QC_MFGID_MSB &&
152 e_addr[2] != QC_CHIPID_SL &&
153 (e_addr[1] == QC_DEVID_SAT1 || e_addr[1] == QC_DEVID_SAT2))
154 return true;
155 return false;
156}
157
Sagar Dharia790cfd02011-09-25 17:56:24 -0600158static struct msm_slim_sat *addr_to_sat(struct msm_slim_ctrl *dev, u8 laddr)
159{
160 struct msm_slim_sat *sat = NULL;
161 int i = 0;
162 while (!sat && i < dev->nsats) {
163 if (laddr == dev->satd[i]->satcl.laddr)
164 sat = dev->satd[i];
165 i++;
166 }
167 return sat;
168}
169
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700170static irqreturn_t msm_slim_interrupt(int irq, void *d)
171{
172 struct msm_slim_ctrl *dev = d;
173 u32 pstat;
174 u32 stat = readl_relaxed(dev->base + MGR_INT_STAT);
175
176 if (stat & MGR_INT_TX_MSG_SENT || stat & MGR_INT_TX_NACKED_2) {
177 if (stat & MGR_INT_TX_MSG_SENT)
178 writel_relaxed(MGR_INT_TX_MSG_SENT,
179 dev->base + MGR_INT_CLR);
180 else {
Sagar Dhariaac913452012-09-04 11:27:26 -0600181 u32 mgr_stat = readl_relaxed(dev->base + MGR_STATUS);
182 u32 mgr_ie_stat = readl_relaxed(dev->base +
183 MGR_IE_STAT);
184 u32 frm_stat = readl_relaxed(dev->base + FRM_STAT);
185 u32 frm_cfg = readl_relaxed(dev->base + FRM_CFG);
186 u32 frm_intr_stat = readl_relaxed(dev->base +
187 FRM_INT_STAT);
188 u32 frm_ie_stat = readl_relaxed(dev->base +
189 FRM_IE_STAT);
190 u32 intf_stat = readl_relaxed(dev->base + INTF_STAT);
191 u32 intf_intr_stat = readl_relaxed(dev->base +
192 INTF_INT_STAT);
193 u32 intf_ie_stat = readl_relaxed(dev->base +
194 INTF_IE_STAT);
195
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700196 writel_relaxed(MGR_INT_TX_NACKED_2,
197 dev->base + MGR_INT_CLR);
Sagar Dhariaac913452012-09-04 11:27:26 -0600198 pr_err("TX Nack MGR dump:int_stat:0x%x, mgr_stat:0x%x",
199 stat, mgr_stat);
200 pr_err("TX Nack MGR dump:ie_stat:0x%x", mgr_ie_stat);
201 pr_err("TX Nack FRM dump:int_stat:0x%x, frm_stat:0x%x",
202 frm_intr_stat, frm_stat);
203 pr_err("TX Nack FRM dump:frm_cfg:0x%x, ie_stat:0x%x",
204 frm_cfg, frm_ie_stat);
205 pr_err("TX Nack INTF dump:intr_st:0x%x, intf_stat:0x%x",
206 intf_intr_stat, intf_stat);
207 pr_err("TX Nack INTF dump:ie_stat:0x%x", intf_ie_stat);
208
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700209 dev->err = -EIO;
210 }
211 /*
212 * Guarantee that interrupt clear bit write goes through before
213 * signalling completion/exiting ISR
214 */
215 mb();
216 if (dev->wr_comp)
217 complete(dev->wr_comp);
218 }
219 if (stat & MGR_INT_RX_MSG_RCVD) {
220 u32 rx_buf[10];
221 u32 mc, mt;
222 u8 len, i;
223 rx_buf[0] = readl_relaxed(dev->base + MGR_RX_MSG);
224 len = rx_buf[0] & 0x1F;
225 for (i = 1; i < ((len + 3) >> 2); i++) {
226 rx_buf[i] = readl_relaxed(dev->base + MGR_RX_MSG +
227 (4 * i));
228 dev_dbg(dev->dev, "reading data: %x\n", rx_buf[i]);
229 }
230 mt = (rx_buf[0] >> 5) & 0x7;
231 mc = (rx_buf[0] >> 8) & 0xff;
232 dev_dbg(dev->dev, "MC: %x, MT: %x\n", mc, mt);
233 if (mt == SLIM_MSG_MT_DEST_REFERRED_USER ||
234 mt == SLIM_MSG_MT_SRC_REFERRED_USER) {
Sagar Dharia790cfd02011-09-25 17:56:24 -0600235 u8 laddr = (u8)((rx_buf[0] >> 16) & 0xFF);
236 struct msm_slim_sat *sat = addr_to_sat(dev, laddr);
237 if (sat)
238 msm_sat_enqueue(sat, rx_buf, len);
239 else
240 dev_err(dev->dev, "unknown sat:%d message",
241 laddr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700242 writel_relaxed(MGR_INT_RX_MSG_RCVD,
243 dev->base + MGR_INT_CLR);
244 /*
245 * Guarantee that CLR bit write goes through before
246 * queuing work
247 */
248 mb();
Sagar Dharia790cfd02011-09-25 17:56:24 -0600249 if (sat)
250 queue_work(sat->wq, &sat->wd);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700251 } else if (mt == SLIM_MSG_MT_CORE &&
252 mc == SLIM_MSG_MC_REPORT_PRESENT) {
253 u8 e_addr[6];
254 msm_get_eaddr(e_addr, rx_buf);
Sagar Dharia790cfd02011-09-25 17:56:24 -0600255 msm_slim_rx_enqueue(dev, rx_buf, len);
256 writel_relaxed(MGR_INT_RX_MSG_RCVD, dev->base +
257 MGR_INT_CLR);
258 /*
259 * Guarantee that CLR bit write goes through
260 * before signalling completion
261 */
262 mb();
263 complete(&dev->rx_msgq_notify);
Kiran Gunda33a23a92013-01-10 17:03:33 +0530264 } else if (mt == SLIM_MSG_MT_CORE &&
265 mc == SLIM_MSG_MC_REPORT_ABSENT) {
266 writel_relaxed(MGR_INT_RX_MSG_RCVD, dev->base +
267 MGR_INT_CLR);
268 /*
269 * Guarantee that CLR bit write goes through
270 * before signalling completion
271 */
272 mb();
273 complete(&dev->rx_msgq_notify);
274
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700275 } else if (mc == SLIM_MSG_MC_REPLY_INFORMATION ||
276 mc == SLIM_MSG_MC_REPLY_VALUE) {
277 msm_slim_rx_enqueue(dev, rx_buf, len);
278 writel_relaxed(MGR_INT_RX_MSG_RCVD, dev->base +
279 MGR_INT_CLR);
280 /*
281 * Guarantee that CLR bit write goes through
282 * before signalling completion
283 */
284 mb();
285 complete(&dev->rx_msgq_notify);
Sagar Dharia144e5e02011-08-08 17:30:11 -0600286 } else if (mc == SLIM_MSG_MC_REPORT_INFORMATION) {
287 u8 *buf = (u8 *)rx_buf;
288 u8 l_addr = buf[2];
289 u16 ele = (u16)buf[4] << 4;
290 ele |= ((buf[3] & 0xf0) >> 4);
291 dev_err(dev->dev, "Slim-dev:%d report inf element:0x%x",
292 l_addr, ele);
293 for (i = 0; i < len - 5; i++)
294 dev_err(dev->dev, "offset:0x%x:bit mask:%x",
295 i, buf[i+5]);
296 writel_relaxed(MGR_INT_RX_MSG_RCVD, dev->base +
297 MGR_INT_CLR);
298 /*
299 * Guarantee that CLR bit write goes through
300 * before exiting
301 */
302 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700303 } else {
304 dev_err(dev->dev, "Unexpected MC,%x MT:%x, len:%d",
305 mc, mt, len);
306 for (i = 0; i < ((len + 3) >> 2); i++)
307 dev_err(dev->dev, "error msg: %x", rx_buf[i]);
308 writel_relaxed(MGR_INT_RX_MSG_RCVD, dev->base +
309 MGR_INT_CLR);
310 /*
311 * Guarantee that CLR bit write goes through
312 * before exiting
313 */
314 mb();
315 }
316 }
317 if (stat & MGR_INT_RECFG_DONE) {
318 writel_relaxed(MGR_INT_RECFG_DONE, dev->base + MGR_INT_CLR);
319 /*
320 * Guarantee that CLR bit write goes through
321 * before exiting ISR
322 */
323 mb();
324 complete(&dev->reconf);
325 }
Sagar Dharia82e516f2012-03-16 16:01:23 -0600326 pstat = readl_relaxed(PGD_THIS_EE(PGD_PORT_INT_ST_EEn, dev->ver));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700327 if (pstat != 0) {
328 int i = 0;
329 for (i = dev->pipe_b; i < MSM_SLIM_NPORTS; i++) {
330 if (pstat & 1 << i) {
Sagar Dharia82e516f2012-03-16 16:01:23 -0600331 u32 val = readl_relaxed(PGD_PORT(PGD_PORT_STATn,
332 i, dev->ver));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700333 if (val & (1 << 19)) {
334 dev->ctrl.ports[i].err =
335 SLIM_P_DISCONNECT;
336 dev->pipes[i-dev->pipe_b].connected =
337 false;
338 /*
339 * SPS will call completion since
340 * ERROR flags are registered
341 */
342 } else if (val & (1 << 2))
343 dev->ctrl.ports[i].err =
344 SLIM_P_OVERFLOW;
345 else if (val & (1 << 3))
346 dev->ctrl.ports[i].err =
347 SLIM_P_UNDERFLOW;
348 }
Sagar Dharia82e516f2012-03-16 16:01:23 -0600349 writel_relaxed(1, PGD_THIS_EE(PGD_PORT_INT_CL_EEn,
350 dev->ver));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700351 }
352 /*
353 * Guarantee that port interrupt bit(s) clearing writes go
354 * through before exiting ISR
355 */
356 mb();
357 }
358
359 return IRQ_HANDLED;
360}
361
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700362static int msm_xfer_msg(struct slim_controller *ctrl, struct slim_msg_txn *txn)
363{
364 DECLARE_COMPLETION_ONSTACK(done);
365 struct msm_slim_ctrl *dev = slim_get_ctrldata(ctrl);
366 u32 *pbuf;
367 u8 *puc;
368 int timeout;
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700369 int msgv = -1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700370 u8 la = txn->la;
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600371 u8 mc = (u8)(txn->mc & 0xFF);
372 /*
373 * Voting for runtime PM: Slimbus has 2 possible use cases:
374 * 1. messaging
375 * 2. Data channels
376 * Messaging case goes through messaging slots and data channels
377 * use their own slots
378 * This "get" votes for messaging bandwidth
379 */
380 if (!(txn->mc & SLIM_MSG_CLK_PAUSE_SEQ_FLG))
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700381 msgv = msm_slim_get_ctrl(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700382 mutex_lock(&dev->tx_lock);
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700383 if (dev->state == MSM_CTRL_ASLEEP ||
384 ((!(txn->mc & SLIM_MSG_CLK_PAUSE_SEQ_FLG)) &&
385 dev->state == MSM_CTRL_SLEEPING)) {
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600386 dev_err(dev->dev, "runtime or system PM suspended state");
387 mutex_unlock(&dev->tx_lock);
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700388 if (msgv >= 0)
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600389 msm_slim_put_ctrl(dev);
390 return -EBUSY;
391 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700392 if (txn->mt == SLIM_MSG_MT_CORE &&
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600393 mc == SLIM_MSG_MC_BEGIN_RECONFIGURATION) {
394 if (dev->reconf_busy) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700395 wait_for_completion(&dev->reconf);
396 dev->reconf_busy = false;
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600397 }
398 /* This "get" votes for data channels */
399 if (dev->ctrl.sched.usedslots != 0 &&
400 !dev->chan_active) {
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700401 int chv = msm_slim_get_ctrl(dev);
402 if (chv >= 0)
403 dev->chan_active = true;
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600404 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700405 }
406 txn->rl--;
Sagar Dharia2754ab42012-08-21 18:07:39 -0600407 pbuf = msm_get_msg_buf(dev, txn->rl);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700408 dev->wr_comp = NULL;
409 dev->err = 0;
410
411 if (txn->dt == SLIM_MSG_DEST_ENUMADDR) {
412 mutex_unlock(&dev->tx_lock);
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700413 if (msgv >= 0)
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600414 msm_slim_put_ctrl(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700415 return -EPROTONOSUPPORT;
416 }
417 if (txn->mt == SLIM_MSG_MT_CORE && txn->la == 0xFF &&
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600418 (mc == SLIM_MSG_MC_CONNECT_SOURCE ||
419 mc == SLIM_MSG_MC_CONNECT_SINK ||
420 mc == SLIM_MSG_MC_DISCONNECT_PORT))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700421 la = dev->pgdla;
422 if (txn->dt == SLIM_MSG_DEST_LOGICALADDR)
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600423 *pbuf = SLIM_MSG_ASM_FIRST_WORD(txn->rl, txn->mt, mc, 0, la);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700424 else
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600425 *pbuf = SLIM_MSG_ASM_FIRST_WORD(txn->rl, txn->mt, mc, 1, la);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700426 if (txn->dt == SLIM_MSG_DEST_LOGICALADDR)
427 puc = ((u8 *)pbuf) + 3;
428 else
429 puc = ((u8 *)pbuf) + 2;
430 if (txn->rbuf)
431 *(puc++) = txn->tid;
432 if ((txn->mt == SLIM_MSG_MT_CORE) &&
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600433 ((mc >= SLIM_MSG_MC_REQUEST_INFORMATION &&
434 mc <= SLIM_MSG_MC_REPORT_INFORMATION) ||
435 (mc >= SLIM_MSG_MC_REQUEST_VALUE &&
436 mc <= SLIM_MSG_MC_CHANGE_VALUE))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700437 *(puc++) = (txn->ec & 0xFF);
438 *(puc++) = (txn->ec >> 8)&0xFF;
439 }
440 if (txn->wbuf)
441 memcpy(puc, txn->wbuf, txn->len);
442 if (txn->mt == SLIM_MSG_MT_CORE && txn->la == 0xFF &&
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600443 (mc == SLIM_MSG_MC_CONNECT_SOURCE ||
444 mc == SLIM_MSG_MC_CONNECT_SINK ||
445 mc == SLIM_MSG_MC_DISCONNECT_PORT)) {
446 if (mc != SLIM_MSG_MC_DISCONNECT_PORT)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700447 dev->err = msm_slim_connect_pipe_port(dev, *puc);
448 else {
449 struct msm_slim_endp *endpoint = &dev->pipes[*puc];
450 struct sps_register_event sps_event;
451 memset(&sps_event, 0, sizeof(sps_event));
452 sps_register_event(endpoint->sps, &sps_event);
453 sps_disconnect(endpoint->sps);
454 /*
455 * Remove channel disconnects master-side ports from
456 * channel. No need to send that again on the bus
457 */
458 dev->pipes[*puc].connected = false;
459 mutex_unlock(&dev->tx_lock);
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700460 if (msgv >= 0)
461 msm_slim_put_ctrl(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700462 return 0;
463 }
464 if (dev->err) {
465 dev_err(dev->dev, "pipe-port connect err:%d", dev->err);
466 mutex_unlock(&dev->tx_lock);
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700467 if (msgv >= 0)
468 msm_slim_put_ctrl(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700469 return dev->err;
470 }
471 *(puc) = *(puc) + dev->pipe_b;
472 }
473 if (txn->mt == SLIM_MSG_MT_CORE &&
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600474 mc == SLIM_MSG_MC_BEGIN_RECONFIGURATION)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700475 dev->reconf_busy = true;
476 dev->wr_comp = &done;
Sagar Dharia2754ab42012-08-21 18:07:39 -0600477 msm_send_msg_buf(dev, pbuf, txn->rl, MGR_TX_MSG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700478 timeout = wait_for_completion_timeout(&done, HZ);
Sagar Dhariaac913452012-09-04 11:27:26 -0600479 if (!timeout)
480 dev->wr_comp = NULL;
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700481 if (mc == SLIM_MSG_MC_RECONFIGURE_NOW) {
482 if ((txn->mc == (SLIM_MSG_MC_RECONFIGURE_NOW |
483 SLIM_MSG_CLK_PAUSE_SEQ_FLG)) &&
484 timeout) {
485 timeout = wait_for_completion_timeout(&dev->reconf, HZ);
486 dev->reconf_busy = false;
487 if (timeout) {
Sagar Dharia9acf7f42012-03-08 09:45:30 -0700488 clk_disable_unprepare(dev->rclk);
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700489 disable_irq(dev->irq);
490 }
491 }
492 if ((txn->mc == (SLIM_MSG_MC_RECONFIGURE_NOW |
493 SLIM_MSG_CLK_PAUSE_SEQ_FLG)) &&
494 !timeout) {
495 dev->reconf_busy = false;
496 dev_err(dev->dev, "clock pause failed");
497 mutex_unlock(&dev->tx_lock);
498 return -ETIMEDOUT;
499 }
500 if (txn->mt == SLIM_MSG_MT_CORE &&
501 txn->mc == SLIM_MSG_MC_RECONFIGURE_NOW) {
502 if (dev->ctrl.sched.usedslots == 0 &&
503 dev->chan_active) {
504 dev->chan_active = false;
505 msm_slim_put_ctrl(dev);
506 }
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600507 }
508 }
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600509 mutex_unlock(&dev->tx_lock);
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700510 if (msgv >= 0)
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600511 msm_slim_put_ctrl(dev);
512
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700513 if (!timeout)
514 dev_err(dev->dev, "TX timed out:MC:0x%x,mt:0x%x", txn->mc,
515 txn->mt);
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600516
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700517 return timeout ? dev->err : -ETIMEDOUT;
518}
519
Sagar Dhariaac913452012-09-04 11:27:26 -0600520static void msm_slim_wait_retry(struct msm_slim_ctrl *dev)
521{
522 int msec_per_frm = 0;
523 int sfr_per_sec;
524 /* Wait for 1 superframe, or default time and then retry */
525 sfr_per_sec = dev->framer.superfreq /
526 (1 << (SLIM_MAX_CLK_GEAR - dev->ctrl.clkgear));
527 if (sfr_per_sec)
528 msec_per_frm = MSEC_PER_SEC / sfr_per_sec;
529 if (msec_per_frm < DEF_RETRY_MS)
530 msec_per_frm = DEF_RETRY_MS;
531 msleep(msec_per_frm);
532}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700533static int msm_set_laddr(struct slim_controller *ctrl, const u8 *ea,
534 u8 elen, u8 laddr)
535{
536 struct msm_slim_ctrl *dev = slim_get_ctrldata(ctrl);
Sagar Dhariaac913452012-09-04 11:27:26 -0600537 struct completion done;
538 int timeout, ret, retries = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700539 u32 *buf;
Sagar Dhariaac913452012-09-04 11:27:26 -0600540retry_laddr:
541 init_completion(&done);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700542 mutex_lock(&dev->tx_lock);
Sagar Dharia2754ab42012-08-21 18:07:39 -0600543 buf = msm_get_msg_buf(dev, 9);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700544 buf[0] = SLIM_MSG_ASM_FIRST_WORD(9, SLIM_MSG_MT_CORE,
545 SLIM_MSG_MC_ASSIGN_LOGICAL_ADDRESS,
546 SLIM_MSG_DEST_LOGICALADDR,
547 ea[5] | ea[4] << 8);
548 buf[1] = ea[3] | (ea[2] << 8) | (ea[1] << 16) | (ea[0] << 24);
549 buf[2] = laddr;
550
551 dev->wr_comp = &done;
Sagar Dharia2754ab42012-08-21 18:07:39 -0600552 ret = msm_send_msg_buf(dev, buf, 9, MGR_TX_MSG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700553 timeout = wait_for_completion_timeout(&done, HZ);
Sagar Dhariaac913452012-09-04 11:27:26 -0600554 if (!timeout)
555 dev->err = -ETIMEDOUT;
556 if (dev->err) {
557 ret = dev->err;
558 dev->err = 0;
559 dev->wr_comp = NULL;
560 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700561 mutex_unlock(&dev->tx_lock);
Sagar Dhariaac913452012-09-04 11:27:26 -0600562 if (ret) {
563 pr_err("set LADDR:0x%x failed:ret:%d, retrying", laddr, ret);
564 if (retries < INIT_MX_RETRIES) {
565 msm_slim_wait_retry(dev);
566 retries++;
567 goto retry_laddr;
568 } else {
569 pr_err("set LADDR failed after retrying:ret:%d", ret);
570 }
571 }
572 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700573}
574
Sagar Dharia144e5e02011-08-08 17:30:11 -0600575static int msm_clk_pause_wakeup(struct slim_controller *ctrl)
576{
577 struct msm_slim_ctrl *dev = slim_get_ctrldata(ctrl);
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600578 enable_irq(dev->irq);
Sagar Dharia9acf7f42012-03-08 09:45:30 -0700579 clk_prepare_enable(dev->rclk);
Sagar Dharia144e5e02011-08-08 17:30:11 -0600580 writel_relaxed(1, dev->base + FRM_WAKEUP);
581 /* Make sure framer wakeup write goes through before exiting function */
582 mb();
583 /*
584 * Workaround: Currently, slave is reporting lost-sync messages
585 * after slimbus comes out of clock pause.
586 * Transaction with slave fail before slave reports that message
587 * Give some time for that report to come
588 * Slimbus wakes up in clock gear 10 at 24.576MHz. With each superframe
589 * being 250 usecs, we wait for 20 superframes here to ensure
590 * we get the message
591 */
592 usleep_range(5000, 5000);
593 return 0;
594}
595
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700596static int msm_sat_define_ch(struct msm_slim_sat *sat, u8 *buf, u8 len, u8 mc)
597{
598 struct msm_slim_ctrl *dev = sat->dev;
599 enum slim_ch_control oper;
600 int i;
601 int ret = 0;
602 if (mc == SLIM_USR_MC_CHAN_CTRL) {
Sagar Dharia0ffdca12011-09-25 18:55:53 -0600603 for (i = 0; i < sat->nsatch; i++) {
604 if (buf[5] == sat->satch[i].chan)
605 break;
606 }
607 if (i >= sat->nsatch)
608 return -ENOTCONN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700609 oper = ((buf[3] & 0xC0) >> 6);
610 /* part of grp. activating/removing 1 will take care of rest */
Sagar Dharia0ffdca12011-09-25 18:55:53 -0600611 ret = slim_control_ch(&sat->satcl, sat->satch[i].chanh, oper,
612 false);
613 if (!ret) {
614 for (i = 5; i < len; i++) {
615 int j;
616 for (j = 0; j < sat->nsatch; j++) {
617 if (buf[i] == sat->satch[j].chan) {
618 if (oper == SLIM_CH_REMOVE)
619 sat->satch[j].req_rem++;
620 else
621 sat->satch[j].req_def++;
622 break;
623 }
624 }
625 }
626 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700627 } else {
628 u16 chh[40];
629 struct slim_ch prop;
630 u32 exp;
Sagar Dhariab886e042012-10-17 22:41:57 -0600631 u16 *grph = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700632 u8 coeff, cc;
633 u8 prrate = buf[6];
Sagar Dharia0ffdca12011-09-25 18:55:53 -0600634 if (len <= 8)
635 return -EINVAL;
636 for (i = 8; i < len; i++) {
637 int j = 0;
638 for (j = 0; j < sat->nsatch; j++) {
639 if (sat->satch[j].chan == buf[i]) {
640 chh[i - 8] = sat->satch[j].chanh;
641 break;
642 }
643 }
644 if (j < sat->nsatch) {
645 u16 dummy;
646 ret = slim_query_ch(&sat->satcl, buf[i],
647 &dummy);
648 if (ret)
649 return ret;
650 if (mc == SLIM_USR_MC_DEF_ACT_CHAN)
651 sat->satch[j].req_def++;
Sagar Dhariab886e042012-10-17 22:41:57 -0600652 /* First channel in group from satellite */
653 if (i == 8)
654 grph = &sat->satch[j].chanh;
Sagar Dharia0ffdca12011-09-25 18:55:53 -0600655 continue;
656 }
657 if (sat->nsatch >= MSM_MAX_SATCH)
658 return -EXFULL;
659 ret = slim_query_ch(&sat->satcl, buf[i], &chh[i - 8]);
660 if (ret)
661 return ret;
662 sat->satch[j].chan = buf[i];
663 sat->satch[j].chanh = chh[i - 8];
664 if (mc == SLIM_USR_MC_DEF_ACT_CHAN)
665 sat->satch[j].req_def++;
Sagar Dhariab886e042012-10-17 22:41:57 -0600666 if (i == 8)
667 grph = &sat->satch[j].chanh;
Sagar Dharia0ffdca12011-09-25 18:55:53 -0600668 sat->nsatch++;
669 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700670 prop.dataf = (enum slim_ch_dataf)((buf[3] & 0xE0) >> 5);
671 prop.auxf = (enum slim_ch_auxf)((buf[4] & 0xC0) >> 5);
672 prop.baser = SLIM_RATE_4000HZ;
673 if (prrate & 0x8)
674 prop.baser = SLIM_RATE_11025HZ;
675 else
676 prop.baser = SLIM_RATE_4000HZ;
677 prop.prot = (enum slim_ch_proto)(buf[5] & 0x0F);
678 prop.sampleszbits = (buf[4] & 0x1F)*SLIM_CL_PER_SL;
679 exp = (u32)((buf[5] & 0xF0) >> 4);
680 coeff = (buf[4] & 0x20) >> 5;
681 cc = (coeff ? 3 : 1);
682 prop.ratem = cc * (1 << exp);
683 if (i > 9)
684 ret = slim_define_ch(&sat->satcl, &prop, chh, len - 8,
Sagar Dharia0ffdca12011-09-25 18:55:53 -0600685 true, &chh[0]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700686 else
687 ret = slim_define_ch(&sat->satcl, &prop,
Sagar Dhariab886e042012-10-17 22:41:57 -0600688 chh, 1, true, &chh[0]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700689 dev_dbg(dev->dev, "define sat grp returned:%d", ret);
Sagar Dharia0ffdca12011-09-25 18:55:53 -0600690 if (ret)
691 return ret;
Sagar Dhariab886e042012-10-17 22:41:57 -0600692 else if (grph)
693 *grph = chh[0];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700694
695 /* part of group so activating 1 will take care of rest */
696 if (mc == SLIM_USR_MC_DEF_ACT_CHAN)
697 ret = slim_control_ch(&sat->satcl,
Sagar Dharia0ffdca12011-09-25 18:55:53 -0600698 chh[0],
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700699 SLIM_CH_ACTIVATE, false);
700 }
701 return ret;
702}
703
704static void msm_slim_rxwq(struct msm_slim_ctrl *dev)
705{
706 u8 buf[40];
707 u8 mc, mt, len;
708 int i, ret;
709 if ((msm_slim_rx_dequeue(dev, (u8 *)buf)) != -ENODATA) {
710 len = buf[0] & 0x1F;
711 mt = (buf[0] >> 5) & 0x7;
712 mc = buf[1];
713 if (mt == SLIM_MSG_MT_CORE &&
714 mc == SLIM_MSG_MC_REPORT_PRESENT) {
715 u8 laddr;
716 u8 e_addr[6];
717 for (i = 0; i < 6; i++)
718 e_addr[i] = buf[7-i];
719
Sagar Dhariaf0b9c752012-09-09 17:32:46 -0600720 ret = slim_assign_laddr(&dev->ctrl, e_addr, 6, &laddr,
721 false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700722 /* Is this Qualcomm ported generic device? */
723 if (!ret && e_addr[5] == QC_MFGID_LSB &&
724 e_addr[4] == QC_MFGID_MSB &&
725 e_addr[1] == QC_DEVID_PGD &&
726 e_addr[2] != QC_CHIPID_SL)
727 dev->pgdla = laddr;
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600728 if (!ret && !pm_runtime_enabled(dev->dev) &&
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700729 laddr == (QC_MSM_DEVS - 1))
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600730 pm_runtime_enable(dev->dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700731
Sagar Dharia790cfd02011-09-25 17:56:24 -0600732 if (!ret && msm_is_sat_dev(e_addr)) {
733 struct msm_slim_sat *sat = addr_to_sat(dev,
734 laddr);
735 if (!sat)
736 sat = msm_slim_alloc_sat(dev);
737 if (!sat)
738 return;
739
740 sat->satcl.laddr = laddr;
741 msm_sat_enqueue(sat, (u32 *)buf, len);
742 queue_work(sat->wq, &sat->wd);
743 }
Sagar Dhariaac913452012-09-04 11:27:26 -0600744 if (ret)
745 pr_err("assign laddr failed, error:%d", ret);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700746 } else if (mc == SLIM_MSG_MC_REPLY_INFORMATION ||
747 mc == SLIM_MSG_MC_REPLY_VALUE) {
748 u8 tid = buf[3];
749 dev_dbg(dev->dev, "tid:%d, len:%d\n", tid, len - 4);
750 slim_msg_response(&dev->ctrl, &buf[4], tid,
751 len - 4);
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700752 pm_runtime_mark_last_busy(dev->dev);
Sagar Dharia144e5e02011-08-08 17:30:11 -0600753 } else if (mc == SLIM_MSG_MC_REPORT_INFORMATION) {
754 u8 l_addr = buf[2];
755 u16 ele = (u16)buf[4] << 4;
756 ele |= ((buf[3] & 0xf0) >> 4);
757 dev_err(dev->dev, "Slim-dev:%d report inf element:0x%x",
758 l_addr, ele);
759 for (i = 0; i < len - 5; i++)
760 dev_err(dev->dev, "offset:0x%x:bit mask:%x",
761 i, buf[i+5]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700762 } else {
763 dev_err(dev->dev, "unexpected message:mc:%x, mt:%x",
764 mc, mt);
765 for (i = 0; i < len; i++)
766 dev_err(dev->dev, "error msg: %x", buf[i]);
767
768 }
769 } else
770 dev_err(dev->dev, "rxwq called and no dequeue");
771}
772
773static void slim_sat_rxprocess(struct work_struct *work)
774{
775 struct msm_slim_sat *sat = container_of(work, struct msm_slim_sat, wd);
776 struct msm_slim_ctrl *dev = sat->dev;
777 u8 buf[40];
778
779 while ((msm_sat_dequeue(sat, buf)) != -ENODATA) {
780 struct slim_msg_txn txn;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700781 u8 len, mc, mt;
782 u32 bw_sl;
783 int ret = 0;
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700784 int satv = -1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700785 bool gen_ack = false;
786 u8 tid;
787 u8 wbuf[8];
Sagar Dhariaac913452012-09-04 11:27:26 -0600788 int i, retries = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700789 txn.mt = SLIM_MSG_MT_SRC_REFERRED_USER;
790 txn.dt = SLIM_MSG_DEST_LOGICALADDR;
791 txn.ec = 0;
792 txn.rbuf = NULL;
793 txn.la = sat->satcl.laddr;
794 /* satellite handling */
795 len = buf[0] & 0x1F;
796 mc = buf[1];
797 mt = (buf[0] >> 5) & 0x7;
798
799 if (mt == SLIM_MSG_MT_CORE &&
800 mc == SLIM_MSG_MC_REPORT_PRESENT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700801 u8 e_addr[6];
802 for (i = 0; i < 6; i++)
803 e_addr[i] = buf[7-i];
804
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600805 if (pm_runtime_enabled(dev->dev)) {
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700806 satv = msm_slim_get_ctrl(dev);
807 if (satv >= 0)
808 sat->pending_capability = true;
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600809 }
Sagar Dharia69bf5572012-02-21 14:45:35 -0700810 /*
811 * Since capability message is already sent, present
812 * message will indicate subsystem hosting this
813 * satellite has restarted.
814 * Remove all active channels of this satellite
815 * when this is detected
816 */
817 if (sat->sent_capability) {
818 for (i = 0; i < sat->nsatch; i++) {
Sagar Dharia1944a132012-08-15 00:01:57 -0600819 if (sat->satch[i].reconf) {
820 pr_err("SSR, sat:%d, rm ch:%d",
Sagar Dhariaac913452012-09-04 11:27:26 -0600821 sat->satcl.laddr,
Sagar Dharia69bf5572012-02-21 14:45:35 -0700822 sat->satch[i].chan);
Sagar Dharia69bf5572012-02-21 14:45:35 -0700823 slim_control_ch(&sat->satcl,
824 sat->satch[i].chanh,
825 SLIM_CH_REMOVE, true);
Sagar Dhariab886e042012-10-17 22:41:57 -0600826 slim_dealloc_ch(&sat->satcl,
827 sat->satch[i].chanh);
Sagar Dharia1944a132012-08-15 00:01:57 -0600828 sat->satch[i].reconf = false;
829 }
Sagar Dharia69bf5572012-02-21 14:45:35 -0700830 }
831 }
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600832 } else if (mt != SLIM_MSG_MT_CORE &&
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700833 mc != SLIM_MSG_MC_REPORT_PRESENT) {
834 satv = msm_slim_get_ctrl(dev);
835 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700836 switch (mc) {
837 case SLIM_MSG_MC_REPORT_PRESENT:
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600838 /* Remove runtime_pm vote once satellite acks */
839 if (mt != SLIM_MSG_MT_CORE) {
840 if (pm_runtime_enabled(dev->dev) &&
841 sat->pending_capability) {
842 msm_slim_put_ctrl(dev);
843 sat->pending_capability = false;
844 }
845 continue;
846 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700847 /* send a Manager capability msg */
Sagar Dharia790cfd02011-09-25 17:56:24 -0600848 if (sat->sent_capability) {
849 if (mt == SLIM_MSG_MT_CORE)
850 goto send_capability;
851 else
852 continue;
853 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700854 ret = slim_add_device(&dev->ctrl, &sat->satcl);
855 if (ret) {
856 dev_err(dev->dev,
857 "Satellite-init failed");
858 continue;
859 }
Sagar Dharia0ffdca12011-09-25 18:55:53 -0600860 /* Satellite-channels */
861 sat->satch = kzalloc(MSM_MAX_SATCH *
862 sizeof(struct msm_sat_chan),
863 GFP_KERNEL);
Sagar Dharia790cfd02011-09-25 17:56:24 -0600864send_capability:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700865 txn.mc = SLIM_USR_MC_MASTER_CAPABILITY;
866 txn.mt = SLIM_MSG_MT_SRC_REFERRED_USER;
867 txn.la = sat->satcl.laddr;
868 txn.rl = 8;
869 wbuf[0] = SAT_MAGIC_LSB;
870 wbuf[1] = SAT_MAGIC_MSB;
871 wbuf[2] = SAT_MSG_VER;
872 wbuf[3] = SAT_MSG_PROT;
873 txn.wbuf = wbuf;
874 txn.len = 4;
Sagar Dhariaac913452012-09-04 11:27:26 -0600875 ret = msm_xfer_msg(&dev->ctrl, &txn);
876 if (ret) {
877 pr_err("capability for:0x%x fail:%d, retry:%d",
878 sat->satcl.laddr, ret, retries);
879 if (retries < INIT_MX_RETRIES) {
880 msm_slim_wait_retry(dev);
881 retries++;
882 goto send_capability;
883 } else {
884 pr_err("failed after all retries:%d",
885 ret);
886 }
887 } else {
888 sat->sent_capability = true;
889 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700890 break;
891 case SLIM_USR_MC_ADDR_QUERY:
892 memcpy(&wbuf[1], &buf[4], 6);
893 ret = slim_get_logical_addr(&sat->satcl,
894 &wbuf[1], 6, &wbuf[7]);
895 if (ret)
896 memset(&wbuf[1], 0, 6);
897 wbuf[0] = buf[3];
898 txn.mc = SLIM_USR_MC_ADDR_REPLY;
899 txn.rl = 12;
900 txn.len = 8;
901 txn.wbuf = wbuf;
902 msm_xfer_msg(&dev->ctrl, &txn);
903 break;
904 case SLIM_USR_MC_DEFINE_CHAN:
905 case SLIM_USR_MC_DEF_ACT_CHAN:
906 case SLIM_USR_MC_CHAN_CTRL:
907 if (mc != SLIM_USR_MC_CHAN_CTRL)
908 tid = buf[7];
909 else
910 tid = buf[4];
911 gen_ack = true;
912 ret = msm_sat_define_ch(sat, buf, len, mc);
913 if (ret) {
914 dev_err(dev->dev,
915 "SAT define_ch returned:%d",
916 ret);
917 }
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600918 if (!sat->pending_reconf) {
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700919 int chv = msm_slim_get_ctrl(dev);
920 if (chv >= 0)
921 sat->pending_reconf = true;
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600922 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700923 break;
924 case SLIM_USR_MC_RECONFIG_NOW:
925 tid = buf[3];
926 gen_ack = true;
927 ret = slim_reconfigure_now(&sat->satcl);
Sagar Dharia0ffdca12011-09-25 18:55:53 -0600928 for (i = 0; i < sat->nsatch; i++) {
929 struct msm_sat_chan *sch = &sat->satch[i];
Sagar Dhariaef444892012-09-05 12:19:24 -0600930 if (sch->req_rem && sch->reconf) {
Sagar Dharia1944a132012-08-15 00:01:57 -0600931 if (!ret) {
Sagar Dharia0ffdca12011-09-25 18:55:53 -0600932 slim_dealloc_ch(&sat->satcl,
933 sch->chanh);
Sagar Dharia1944a132012-08-15 00:01:57 -0600934 sch->reconf = false;
935 }
Sagar Dharia0ffdca12011-09-25 18:55:53 -0600936 sch->req_rem--;
937 } else if (sch->req_def) {
938 if (ret)
939 slim_dealloc_ch(&sat->satcl,
940 sch->chanh);
Sagar Dharia1944a132012-08-15 00:01:57 -0600941 else
942 sch->reconf = true;
Sagar Dharia0ffdca12011-09-25 18:55:53 -0600943 sch->req_def--;
944 }
945 }
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600946 if (sat->pending_reconf) {
947 msm_slim_put_ctrl(dev);
948 sat->pending_reconf = false;
949 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700950 break;
951 case SLIM_USR_MC_REQ_BW:
952 /* what we get is in SLOTS */
953 bw_sl = (u32)buf[4] << 3 |
954 ((buf[3] & 0xE0) >> 5);
955 sat->satcl.pending_msgsl = bw_sl;
956 tid = buf[5];
957 gen_ack = true;
958 break;
959 case SLIM_USR_MC_CONNECT_SRC:
960 case SLIM_USR_MC_CONNECT_SINK:
961 if (mc == SLIM_USR_MC_CONNECT_SRC)
962 txn.mc = SLIM_MSG_MC_CONNECT_SOURCE;
963 else
964 txn.mc = SLIM_MSG_MC_CONNECT_SINK;
965 wbuf[0] = buf[4] & 0x1F;
966 wbuf[1] = buf[5];
967 tid = buf[6];
968 txn.la = buf[3];
969 txn.mt = SLIM_MSG_MT_CORE;
970 txn.rl = 6;
971 txn.len = 2;
972 txn.wbuf = wbuf;
973 gen_ack = true;
974 ret = msm_xfer_msg(&dev->ctrl, &txn);
975 break;
976 case SLIM_USR_MC_DISCONNECT_PORT:
977 txn.mc = SLIM_MSG_MC_DISCONNECT_PORT;
978 wbuf[0] = buf[4] & 0x1F;
979 tid = buf[5];
980 txn.la = buf[3];
981 txn.rl = 5;
982 txn.len = 1;
983 txn.mt = SLIM_MSG_MT_CORE;
984 txn.wbuf = wbuf;
985 gen_ack = true;
986 ret = msm_xfer_msg(&dev->ctrl, &txn);
Kiran Gunda33a23a92013-01-10 17:03:33 +0530987 break;
988 case SLIM_MSG_MC_REPORT_ABSENT:
989 dev_info(dev->dev, "Received Report Absent Message\n");
990 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700991 default:
992 break;
993 }
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600994 if (!gen_ack) {
Sagar Dhariad3ef30a2011-12-09 14:30:45 -0700995 if (mc != SLIM_MSG_MC_REPORT_PRESENT && satv >= 0)
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600996 msm_slim_put_ctrl(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700997 continue;
Sagar Dharia45ee38a2011-08-03 17:01:31 -0600998 }
999
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001000 wbuf[0] = tid;
1001 if (!ret)
1002 wbuf[1] = MSM_SAT_SUCCSS;
1003 else
1004 wbuf[1] = 0;
1005 txn.mc = SLIM_USR_MC_GENERIC_ACK;
1006 txn.la = sat->satcl.laddr;
1007 txn.rl = 6;
1008 txn.len = 2;
1009 txn.wbuf = wbuf;
1010 txn.mt = SLIM_MSG_MT_SRC_REFERRED_USER;
1011 msm_xfer_msg(&dev->ctrl, &txn);
Sagar Dhariad3ef30a2011-12-09 14:30:45 -07001012 if (satv >= 0)
1013 msm_slim_put_ctrl(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001014 }
1015}
1016
Sagar Dharia790cfd02011-09-25 17:56:24 -06001017static struct msm_slim_sat *msm_slim_alloc_sat(struct msm_slim_ctrl *dev)
1018{
1019 struct msm_slim_sat *sat;
1020 char *name;
1021 if (dev->nsats >= MSM_MAX_NSATS)
1022 return NULL;
1023
1024 sat = kzalloc(sizeof(struct msm_slim_sat), GFP_KERNEL);
1025 if (!sat) {
1026 dev_err(dev->dev, "no memory for satellite");
1027 return NULL;
1028 }
1029 name = kzalloc(SLIMBUS_NAME_SIZE, GFP_KERNEL);
1030 if (!name) {
1031 dev_err(dev->dev, "no memory for satellite name");
1032 kfree(sat);
1033 return NULL;
1034 }
1035 dev->satd[dev->nsats] = sat;
1036 sat->dev = dev;
1037 snprintf(name, SLIMBUS_NAME_SIZE, "msm_sat%d", dev->nsats);
1038 sat->satcl.name = name;
1039 spin_lock_init(&sat->lock);
1040 INIT_WORK(&sat->wd, slim_sat_rxprocess);
1041 sat->wq = create_singlethread_workqueue(sat->satcl.name);
1042 if (!sat->wq) {
1043 kfree(name);
1044 kfree(sat);
1045 return NULL;
1046 }
1047 /*
1048 * Both sats will be allocated from RX thread and RX thread will
1049 * process messages sequentially. No synchronization necessary
1050 */
1051 dev->nsats++;
1052 return sat;
1053}
1054
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001055static int msm_slim_rx_msgq_thread(void *data)
1056{
1057 struct msm_slim_ctrl *dev = (struct msm_slim_ctrl *)data;
1058 struct completion *notify = &dev->rx_msgq_notify;
1059 struct msm_slim_sat *sat = NULL;
1060 u32 mc = 0;
1061 u32 mt = 0;
1062 u32 buffer[10];
1063 int index = 0;
1064 u8 msg_len = 0;
1065 int ret;
1066
1067 dev_dbg(dev->dev, "rx thread started");
1068
1069 while (!kthread_should_stop()) {
1070 set_current_state(TASK_INTERRUPTIBLE);
1071 ret = wait_for_completion_interruptible(notify);
1072
1073 if (ret)
1074 dev_err(dev->dev, "rx thread wait error:%d", ret);
1075
1076 /* 1 irq notification per message */
Sagar Dharia24419e32013-01-14 17:56:32 -07001077 if (dev->use_rx_msgqs != MSM_MSGQ_ENABLED) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001078 msm_slim_rxwq(dev);
1079 continue;
1080 }
1081
1082 ret = msm_slim_rx_msgq_get(dev, buffer, index);
1083 if (ret) {
1084 dev_err(dev->dev, "rx_msgq_get() failed 0x%x\n", ret);
1085 continue;
1086 }
1087
1088 pr_debug("message[%d] = 0x%x\n", index, *buffer);
1089
1090 /* Decide if we use generic RX or satellite RX */
1091 if (index++ == 0) {
1092 msg_len = *buffer & 0x1F;
1093 pr_debug("Start of new message, len = %d\n", msg_len);
1094 mt = (buffer[0] >> 5) & 0x7;
1095 mc = (buffer[0] >> 8) & 0xff;
1096 dev_dbg(dev->dev, "MC: %x, MT: %x\n", mc, mt);
1097 if (mt == SLIM_MSG_MT_DEST_REFERRED_USER ||
Sagar Dharia790cfd02011-09-25 17:56:24 -06001098 mt == SLIM_MSG_MT_SRC_REFERRED_USER) {
1099 u8 laddr;
1100 laddr = (u8)((buffer[0] >> 16) & 0xff);
1101 sat = addr_to_sat(dev, laddr);
1102 }
Kiran Gunda33a23a92013-01-10 17:03:33 +05301103 }
1104 if ((index * 4) >= msg_len) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001105 index = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001106 if (sat) {
1107 msm_sat_enqueue(sat, buffer, msg_len);
1108 queue_work(sat->wq, &sat->wd);
1109 sat = NULL;
1110 } else {
1111 msm_slim_rx_enqueue(dev, buffer, msg_len);
1112 msm_slim_rxwq(dev);
1113 }
1114 }
1115 }
1116
1117 return 0;
1118}
1119
Sagar Dhariacc969452011-09-19 10:34:30 -06001120static void msm_slim_prg_slew(struct platform_device *pdev,
1121 struct msm_slim_ctrl *dev)
1122{
1123 struct resource *slew_io;
1124 void __iomem *slew_reg;
1125 /* SLEW RATE register for this slimbus */
1126 dev->slew_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
1127 "slimbus_slew_reg");
1128 if (!dev->slew_mem) {
1129 dev_dbg(&pdev->dev, "no slimbus slew resource\n");
1130 return;
1131 }
1132 slew_io = request_mem_region(dev->slew_mem->start,
1133 resource_size(dev->slew_mem), pdev->name);
1134 if (!slew_io) {
1135 dev_dbg(&pdev->dev, "slimbus-slew mem claimed\n");
1136 dev->slew_mem = NULL;
1137 return;
1138 }
1139
1140 slew_reg = ioremap(dev->slew_mem->start, resource_size(dev->slew_mem));
1141 if (!slew_reg) {
1142 dev_dbg(dev->dev, "slew register mapping failed");
1143 release_mem_region(dev->slew_mem->start,
1144 resource_size(dev->slew_mem));
1145 dev->slew_mem = NULL;
1146 return;
1147 }
1148 writel_relaxed(1, slew_reg);
1149 /* Make sure slimbus-slew rate enabling goes through */
1150 wmb();
1151 iounmap(slew_reg);
1152}
1153
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001154static int __devinit msm_slim_probe(struct platform_device *pdev)
1155{
1156 struct msm_slim_ctrl *dev;
1157 int ret;
Joonwoo Parkf69f77a2012-08-28 15:26:11 -07001158 enum apr_subsys_state q6_state;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001159 struct resource *bam_mem, *bam_io;
1160 struct resource *slim_mem, *slim_io;
1161 struct resource *irq, *bam_irq;
Sagar Dharia1beb2202012-07-31 19:06:21 -06001162 bool rxreg_access = false;
Joonwoo Parkf69f77a2012-08-28 15:26:11 -07001163
1164 q6_state = apr_get_q6_state();
1165 if (q6_state == APR_SUBSYS_DOWN) {
1166 dev_dbg(&pdev->dev, "defering %s, adsp_state %d\n", __func__,
1167 q6_state);
1168 return -EPROBE_DEFER;
1169 } else
1170 dev_dbg(&pdev->dev, "adsp is ready\n");
1171
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001172 slim_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
1173 "slimbus_physical");
1174 if (!slim_mem) {
1175 dev_err(&pdev->dev, "no slimbus physical memory resource\n");
1176 return -ENODEV;
1177 }
1178 slim_io = request_mem_region(slim_mem->start, resource_size(slim_mem),
1179 pdev->name);
1180 if (!slim_io) {
1181 dev_err(&pdev->dev, "slimbus memory already claimed\n");
1182 return -EBUSY;
1183 }
1184
1185 bam_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
1186 "slimbus_bam_physical");
1187 if (!bam_mem) {
1188 dev_err(&pdev->dev, "no slimbus BAM memory resource\n");
1189 ret = -ENODEV;
1190 goto err_get_res_bam_failed;
1191 }
1192 bam_io = request_mem_region(bam_mem->start, resource_size(bam_mem),
1193 pdev->name);
1194 if (!bam_io) {
1195 release_mem_region(slim_mem->start, resource_size(slim_mem));
1196 dev_err(&pdev->dev, "slimbus BAM memory already claimed\n");
1197 ret = -EBUSY;
1198 goto err_get_res_bam_failed;
1199 }
1200 irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
1201 "slimbus_irq");
1202 if (!irq) {
1203 dev_err(&pdev->dev, "no slimbus IRQ resource\n");
1204 ret = -ENODEV;
1205 goto err_get_res_failed;
1206 }
1207 bam_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
1208 "slimbus_bam_irq");
1209 if (!bam_irq) {
1210 dev_err(&pdev->dev, "no slimbus BAM IRQ resource\n");
1211 ret = -ENODEV;
1212 goto err_get_res_failed;
1213 }
1214
1215 dev = kzalloc(sizeof(struct msm_slim_ctrl), GFP_KERNEL);
1216 if (!dev) {
1217 dev_err(&pdev->dev, "no memory for MSM slimbus controller\n");
1218 ret = -ENOMEM;
1219 goto err_get_res_failed;
1220 }
1221 dev->dev = &pdev->dev;
1222 platform_set_drvdata(pdev, dev);
1223 slim_set_ctrldata(&dev->ctrl, dev);
1224 dev->base = ioremap(slim_mem->start, resource_size(slim_mem));
1225 if (!dev->base) {
1226 dev_err(&pdev->dev, "IOremap failed\n");
1227 ret = -ENOMEM;
1228 goto err_ioremap_failed;
1229 }
1230 dev->bam.base = ioremap(bam_mem->start, resource_size(bam_mem));
1231 if (!dev->bam.base) {
1232 dev_err(&pdev->dev, "BAM IOremap failed\n");
1233 ret = -ENOMEM;
1234 goto err_ioremap_bam_failed;
1235 }
Sagar Dhariaf8f603b2012-03-21 15:25:17 -06001236 if (pdev->dev.of_node) {
1237
1238 ret = of_property_read_u32(pdev->dev.of_node, "cell-index",
1239 &dev->ctrl.nr);
1240 if (ret) {
1241 dev_err(&pdev->dev, "Cell index not specified:%d", ret);
1242 goto err_of_init_failed;
1243 }
Sagar Dharia1beb2202012-07-31 19:06:21 -06001244 rxreg_access = of_property_read_bool(pdev->dev.of_node,
1245 "qcom,rxreg-access");
Sagar Dhariaf8f603b2012-03-21 15:25:17 -06001246 /* Optional properties */
1247 ret = of_property_read_u32(pdev->dev.of_node,
1248 "qcom,min-clk-gear", &dev->ctrl.min_cg);
1249 ret = of_property_read_u32(pdev->dev.of_node,
1250 "qcom,max-clk-gear", &dev->ctrl.max_cg);
Sagar Dharia1beb2202012-07-31 19:06:21 -06001251 pr_debug("min_cg:%d, max_cg:%d, rxreg: %d", dev->ctrl.min_cg,
1252 dev->ctrl.max_cg, rxreg_access);
Sagar Dhariaf8f603b2012-03-21 15:25:17 -06001253 } else {
1254 dev->ctrl.nr = pdev->id;
1255 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001256 dev->ctrl.nchans = MSM_SLIM_NCHANS;
1257 dev->ctrl.nports = MSM_SLIM_NPORTS;
1258 dev->ctrl.set_laddr = msm_set_laddr;
1259 dev->ctrl.xfer_msg = msm_xfer_msg;
Sagar Dharia144e5e02011-08-08 17:30:11 -06001260 dev->ctrl.wakeup = msm_clk_pause_wakeup;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001261 dev->ctrl.config_port = msm_config_port;
1262 dev->ctrl.port_xfer = msm_slim_port_xfer;
1263 dev->ctrl.port_xfer_status = msm_slim_port_xfer_status;
1264 /* Reserve some messaging BW for satellite-apps driver communication */
1265 dev->ctrl.sched.pending_msgsl = 30;
1266
1267 init_completion(&dev->reconf);
1268 mutex_init(&dev->tx_lock);
1269 spin_lock_init(&dev->rx_lock);
1270 dev->ee = 1;
Sagar Dharia1beb2202012-07-31 19:06:21 -06001271 if (rxreg_access)
Sagar Dharia24419e32013-01-14 17:56:32 -07001272 dev->use_rx_msgqs = MSM_MSGQ_DISABLED;
Sagar Dharia1beb2202012-07-31 19:06:21 -06001273 else
Sagar Dharia24419e32013-01-14 17:56:32 -07001274 dev->use_rx_msgqs = MSM_MSGQ_RESET;
Sagar Dharia1beb2202012-07-31 19:06:21 -06001275
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001276 dev->irq = irq->start;
1277 dev->bam.irq = bam_irq->start;
1278
Sagar Dhariadebc8b72012-08-11 15:02:12 -06001279 dev->hclk = clk_get(dev->dev, "iface_clk");
1280 if (IS_ERR(dev->hclk))
1281 dev->hclk = NULL;
1282 else
1283 clk_prepare_enable(dev->hclk);
1284
Sagar Dharia60f59a72012-10-17 12:42:03 -06001285 ret = msm_slim_sps_init(dev, bam_mem, MGR_STATUS, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001286 if (ret != 0) {
1287 dev_err(dev->dev, "error SPS init\n");
1288 goto err_sps_init_failed;
1289 }
1290
Sagar Dharia2754ab42012-08-21 18:07:39 -06001291 /* Fire up the Rx message queue thread */
1292 dev->rx_msgq_thread = kthread_run(msm_slim_rx_msgq_thread, dev,
1293 MSM_SLIM_NAME "_rx_msgq_thread");
1294 if (IS_ERR(dev->rx_msgq_thread)) {
1295 ret = PTR_ERR(dev->rx_msgq_thread);
1296 dev_err(dev->dev, "Failed to start Rx message queue thread\n");
1297 goto err_thread_create_failed;
1298 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001299
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001300 dev->framer.rootfreq = SLIM_ROOT_FREQ >> 3;
1301 dev->framer.superfreq =
1302 dev->framer.rootfreq / SLIM_CL_PER_SUPERFRAME_DIV8;
1303 dev->ctrl.a_framer = &dev->framer;
1304 dev->ctrl.clkgear = SLIM_MAX_CLK_GEAR;
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001305 dev->ctrl.dev.parent = &pdev->dev;
Sagar Dhariaf8f603b2012-03-21 15:25:17 -06001306 dev->ctrl.dev.of_node = pdev->dev.of_node;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001307
1308 ret = request_irq(dev->irq, msm_slim_interrupt, IRQF_TRIGGER_HIGH,
1309 "msm_slim_irq", dev);
1310 if (ret) {
1311 dev_err(&pdev->dev, "request IRQ failed\n");
1312 goto err_request_irq_failed;
1313 }
1314
Sagar Dhariacc969452011-09-19 10:34:30 -06001315 msm_slim_prg_slew(pdev, dev);
Sagar Dhariab1c0acf2012-02-06 18:16:58 -07001316
1317 /* Register with framework before enabling frame, clock */
1318 ret = slim_add_numbered_controller(&dev->ctrl);
1319 if (ret) {
1320 dev_err(dev->dev, "error adding controller\n");
1321 goto err_ctrl_failed;
1322 }
1323
1324
Tianyi Gou44a81b02012-02-06 17:49:07 -08001325 dev->rclk = clk_get(dev->dev, "core_clk");
Sagar Dhariab1c0acf2012-02-06 18:16:58 -07001326 if (!dev->rclk) {
1327 dev_err(dev->dev, "slimbus clock not found");
1328 goto err_clk_get_failed;
1329 }
Sagar Dhariacc969452011-09-19 10:34:30 -06001330 clk_set_rate(dev->rclk, SLIM_ROOT_FREQ);
Sagar Dharia9acf7f42012-03-08 09:45:30 -07001331 clk_prepare_enable(dev->rclk);
Sagar Dhariacc969452011-09-19 10:34:30 -06001332
Sagar Dharia82e516f2012-03-16 16:01:23 -06001333 dev->ver = readl_relaxed(dev->base);
1334 /* Version info in 16 MSbits */
1335 dev->ver >>= 16;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001336 /* Component register initialization */
Sagar Dharia82e516f2012-03-16 16:01:23 -06001337 writel_relaxed(1, dev->base + CFG_PORT(COMP_CFG, dev->ver));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001338 writel_relaxed((EE_MGR_RSC_GRP | EE_NGD_2 | EE_NGD_1),
Sagar Dharia82e516f2012-03-16 16:01:23 -06001339 dev->base + CFG_PORT(COMP_TRUST_CFG, dev->ver));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001340
1341 /*
1342 * Manager register initialization
1343 * If RX msg Q is used, disable RX_MSG_RCVD interrupt
1344 */
Sagar Dharia24419e32013-01-14 17:56:32 -07001345 if (dev->use_rx_msgqs == MSM_MSGQ_ENABLED)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001346 writel_relaxed((MGR_INT_RECFG_DONE | MGR_INT_TX_NACKED_2 |
1347 MGR_INT_MSG_BUF_CONTE | /* MGR_INT_RX_MSG_RCVD | */
1348 MGR_INT_TX_MSG_SENT), dev->base + MGR_INT_EN);
1349 else
1350 writel_relaxed((MGR_INT_RECFG_DONE | MGR_INT_TX_NACKED_2 |
1351 MGR_INT_MSG_BUF_CONTE | MGR_INT_RX_MSG_RCVD |
1352 MGR_INT_TX_MSG_SENT), dev->base + MGR_INT_EN);
1353 writel_relaxed(1, dev->base + MGR_CFG);
1354 /*
1355 * Framer registers are beyond 1K memory region after Manager and/or
1356 * component registers. Make sure those writes are ordered
1357 * before framer register writes
1358 */
1359 wmb();
1360
1361 /* Framer register initialization */
Sagar Dhariadebc8b72012-08-11 15:02:12 -06001362 writel_relaxed((1 << INTR_WAKE) | (0xA << REF_CLK_GEAR) |
1363 (0xA << CLK_GEAR) | (1 << ROOT_FREQ) | (1 << FRM_ACTIVE) | 1,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001364 dev->base + FRM_CFG);
1365 /*
1366 * Make sure that framer wake-up and enabling writes go through
1367 * before any other component is enabled. Framer is responsible for
1368 * clocking the bus and enabling framer first will ensure that other
1369 * devices can report presence when they are enabled
1370 */
1371 mb();
1372
1373 /* Enable RX msg Q */
Sagar Dharia24419e32013-01-14 17:56:32 -07001374 if (dev->use_rx_msgqs == MSM_MSGQ_ENABLED)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001375 writel_relaxed(MGR_CFG_ENABLE | MGR_CFG_RX_MSGQ_EN,
1376 dev->base + MGR_CFG);
1377 else
1378 writel_relaxed(MGR_CFG_ENABLE, dev->base + MGR_CFG);
1379 /*
1380 * Make sure that manager-enable is written through before interface
1381 * device is enabled
1382 */
1383 mb();
1384 writel_relaxed(1, dev->base + INTF_CFG);
1385 /*
1386 * Make sure that interface-enable is written through before enabling
1387 * ported generic device inside MSM manager
1388 */
1389 mb();
Sagar Dharia82e516f2012-03-16 16:01:23 -06001390 writel_relaxed(1, dev->base + CFG_PORT(PGD_CFG, dev->ver));
1391 writel_relaxed(0x3F<<17, dev->base + CFG_PORT(PGD_OWN_EEn, dev->ver) +
1392 (4 * dev->ee));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001393 /*
1394 * Make sure that ported generic device is enabled and port-EE settings
1395 * are written through before finally enabling the component
1396 */
1397 mb();
1398
Sagar Dharia82e516f2012-03-16 16:01:23 -06001399 writel_relaxed(1, dev->base + CFG_PORT(COMP_CFG, dev->ver));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001400 /*
1401 * Make sure that all writes have gone through before exiting this
1402 * function
1403 */
1404 mb();
Sagar Dhariaa6627e02012-08-28 12:20:49 -06001405
1406 /* Add devices registered with board-info now that controller is up */
1407 slim_ctrl_add_boarddevs(&dev->ctrl);
1408
Sagar Dhariaf8f603b2012-03-21 15:25:17 -06001409 if (pdev->dev.of_node)
1410 of_register_slim_devices(&dev->ctrl);
1411
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001412 pm_runtime_use_autosuspend(&pdev->dev);
1413 pm_runtime_set_autosuspend_delay(&pdev->dev, MSM_SLIM_AUTOSUSPEND);
1414 pm_runtime_set_active(&pdev->dev);
1415
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001416 dev_dbg(dev->dev, "MSM SB controller is up!\n");
1417 return 0;
1418
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001419err_ctrl_failed:
Sagar Dharia82e516f2012-03-16 16:01:23 -06001420 writel_relaxed(0, dev->base + CFG_PORT(COMP_CFG, dev->ver));
Sagar Dhariab1c0acf2012-02-06 18:16:58 -07001421err_clk_get_failed:
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001422 kfree(dev->satd);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001423err_request_irq_failed:
Sagar Dharia2754ab42012-08-21 18:07:39 -06001424 kthread_stop(dev->rx_msgq_thread);
1425err_thread_create_failed:
Sagar Dharia33beca02012-10-22 16:21:46 -06001426 msm_slim_sps_exit(dev, true);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001427err_sps_init_failed:
Sagar Dhariadebc8b72012-08-11 15:02:12 -06001428 if (dev->hclk) {
1429 clk_disable_unprepare(dev->hclk);
1430 clk_put(dev->hclk);
1431 }
Sagar Dhariaf8f603b2012-03-21 15:25:17 -06001432err_of_init_failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001433 iounmap(dev->bam.base);
1434err_ioremap_bam_failed:
1435 iounmap(dev->base);
1436err_ioremap_failed:
1437 kfree(dev);
1438err_get_res_failed:
1439 release_mem_region(bam_mem->start, resource_size(bam_mem));
1440err_get_res_bam_failed:
1441 release_mem_region(slim_mem->start, resource_size(slim_mem));
1442 return ret;
1443}
1444
1445static int __devexit msm_slim_remove(struct platform_device *pdev)
1446{
1447 struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
1448 struct resource *bam_mem;
1449 struct resource *slim_mem;
Sagar Dhariacc969452011-09-19 10:34:30 -06001450 struct resource *slew_mem = dev->slew_mem;
Sagar Dharia790cfd02011-09-25 17:56:24 -06001451 int i;
1452 for (i = 0; i < dev->nsats; i++) {
1453 struct msm_slim_sat *sat = dev->satd[i];
Sagar Dharia0ffdca12011-09-25 18:55:53 -06001454 int j;
1455 for (j = 0; j < sat->nsatch; j++)
1456 slim_dealloc_ch(&sat->satcl, sat->satch[j].chanh);
Sagar Dharia790cfd02011-09-25 17:56:24 -06001457 slim_remove_device(&sat->satcl);
1458 kfree(sat->satch);
1459 destroy_workqueue(sat->wq);
1460 kfree(sat->satcl.name);
1461 kfree(sat);
1462 }
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001463 pm_runtime_disable(&pdev->dev);
1464 pm_runtime_set_suspended(&pdev->dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001465 free_irq(dev->irq, dev);
1466 slim_del_controller(&dev->ctrl);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001467 clk_put(dev->rclk);
Sagar Dhariadebc8b72012-08-11 15:02:12 -06001468 if (dev->hclk)
1469 clk_put(dev->hclk);
Sagar Dharia33beca02012-10-22 16:21:46 -06001470 msm_slim_sps_exit(dev, true);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001471 kthread_stop(dev->rx_msgq_thread);
1472 iounmap(dev->bam.base);
1473 iounmap(dev->base);
1474 kfree(dev);
1475 bam_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
1476 "slimbus_bam_physical");
Sagar Dhariae77961f2011-09-27 14:03:50 -06001477 if (bam_mem)
1478 release_mem_region(bam_mem->start, resource_size(bam_mem));
Sagar Dhariacc969452011-09-19 10:34:30 -06001479 if (slew_mem)
1480 release_mem_region(slew_mem->start, resource_size(slew_mem));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001481 slim_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
1482 "slimbus_physical");
Sagar Dhariae77961f2011-09-27 14:03:50 -06001483 if (slim_mem)
1484 release_mem_region(slim_mem->start, resource_size(slim_mem));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001485 return 0;
1486}
1487
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001488#ifdef CONFIG_PM_RUNTIME
1489static int msm_slim_runtime_idle(struct device *device)
1490{
1491 dev_dbg(device, "pm_runtime: idle...\n");
1492 pm_request_autosuspend(device);
1493 return -EAGAIN;
1494}
1495#endif
1496
1497/*
1498 * If PM_RUNTIME is not defined, these 2 functions become helper
1499 * functions to be called from system suspend/resume. So they are not
1500 * inside ifdef CONFIG_PM_RUNTIME
1501 */
Sagar Dharia45e77912012-01-10 09:55:18 -07001502#ifdef CONFIG_PM_SLEEP
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001503static int msm_slim_runtime_suspend(struct device *device)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001504{
1505 struct platform_device *pdev = to_platform_device(device);
1506 struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001507 int ret;
1508 dev_dbg(device, "pm_runtime: suspending...\n");
1509 dev->state = MSM_CTRL_SLEEPING;
1510 ret = slim_ctrl_clk_pause(&dev->ctrl, false, SLIM_CLK_UNSPECIFIED);
Sagar Dhariad3ef30a2011-12-09 14:30:45 -07001511 if (ret) {
1512 dev_err(device, "clk pause not entered:%d", ret);
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001513 dev->state = MSM_CTRL_AWAKE;
Sagar Dhariad3ef30a2011-12-09 14:30:45 -07001514 } else {
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001515 dev->state = MSM_CTRL_ASLEEP;
Sagar Dhariad3ef30a2011-12-09 14:30:45 -07001516 }
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001517 return ret;
1518}
1519
1520static int msm_slim_runtime_resume(struct device *device)
1521{
1522 struct platform_device *pdev = to_platform_device(device);
1523 struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
1524 int ret = 0;
1525 dev_dbg(device, "pm_runtime: resuming...\n");
1526 if (dev->state == MSM_CTRL_ASLEEP)
1527 ret = slim_ctrl_clk_pause(&dev->ctrl, true, 0);
Sagar Dhariad3ef30a2011-12-09 14:30:45 -07001528 if (ret) {
1529 dev_err(device, "clk pause not exited:%d", ret);
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001530 dev->state = MSM_CTRL_ASLEEP;
Sagar Dhariad3ef30a2011-12-09 14:30:45 -07001531 } else {
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001532 dev->state = MSM_CTRL_AWAKE;
Sagar Dhariad3ef30a2011-12-09 14:30:45 -07001533 }
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001534 return ret;
1535}
1536
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001537static int msm_slim_suspend(struct device *dev)
1538{
1539 int ret = 0;
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 dev_dbg(dev, "system suspend");
1544 ret = msm_slim_runtime_suspend(dev);
Sagar Dhariadebc8b72012-08-11 15:02:12 -06001545 if (!ret) {
1546 if (cdev->hclk)
1547 clk_disable_unprepare(cdev->hclk);
1548 }
Sagar Dharia6b559e02011-08-03 17:01:31 -06001549 }
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001550 if (ret == -EBUSY) {
Sagar Dharia144e5e02011-08-08 17:30:11 -06001551 /*
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001552 * If the clock pause failed due to active channels, there is
1553 * a possibility that some audio stream is active during suspend
1554 * We dont want to return suspend failure in that case so that
1555 * display and relevant components can still go to suspend.
1556 * If there is some other error, then it should be passed-on
1557 * to system level suspend
1558 */
Sagar Dharia144e5e02011-08-08 17:30:11 -06001559 ret = 0;
1560 }
1561 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001562}
1563
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001564static int msm_slim_resume(struct device *dev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001565{
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001566 /* If runtime_pm is enabled, this resume shouldn't do anything */
1567 if (!pm_runtime_enabled(dev) || !pm_runtime_suspended(dev)) {
Sagar Dhariadebc8b72012-08-11 15:02:12 -06001568 struct platform_device *pdev = to_platform_device(dev);
1569 struct msm_slim_ctrl *cdev = platform_get_drvdata(pdev);
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001570 int ret;
1571 dev_dbg(dev, "system resume");
Sagar Dhariadebc8b72012-08-11 15:02:12 -06001572 if (cdev->hclk)
1573 clk_prepare_enable(cdev->hclk);
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001574 ret = msm_slim_runtime_resume(dev);
1575 if (!ret) {
1576 pm_runtime_mark_last_busy(dev);
1577 pm_request_autosuspend(dev);
1578 }
1579 return ret;
1580
Sagar Dharia144e5e02011-08-08 17:30:11 -06001581 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001582 return 0;
1583}
Sagar Dharia45ee38a2011-08-03 17:01:31 -06001584#endif /* CONFIG_PM_SLEEP */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001585
1586static const struct dev_pm_ops msm_slim_dev_pm_ops = {
1587 SET_SYSTEM_SLEEP_PM_OPS(
1588 msm_slim_suspend,
1589 msm_slim_resume
1590 )
1591 SET_RUNTIME_PM_OPS(
1592 msm_slim_runtime_suspend,
1593 msm_slim_runtime_resume,
1594 msm_slim_runtime_idle
1595 )
1596};
1597
Sagar Dhariaf8f603b2012-03-21 15:25:17 -06001598static struct of_device_id msm_slim_dt_match[] = {
1599 {
1600 .compatible = "qcom,slim-msm",
1601 },
1602 {}
1603};
1604
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001605static struct platform_driver msm_slim_driver = {
1606 .probe = msm_slim_probe,
1607 .remove = msm_slim_remove,
1608 .driver = {
1609 .name = MSM_SLIM_NAME,
1610 .owner = THIS_MODULE,
1611 .pm = &msm_slim_dev_pm_ops,
Sagar Dhariaf8f603b2012-03-21 15:25:17 -06001612 .of_match_table = msm_slim_dt_match,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001613 },
1614};
1615
1616static int msm_slim_init(void)
1617{
1618 return platform_driver_register(&msm_slim_driver);
1619}
1620subsys_initcall(msm_slim_init);
1621
1622static void msm_slim_exit(void)
1623{
1624 platform_driver_unregister(&msm_slim_driver);
1625}
1626module_exit(msm_slim_exit);
1627
1628MODULE_LICENSE("GPL v2");
1629MODULE_VERSION("0.1");
1630MODULE_DESCRIPTION("MSM Slimbus controller");
1631MODULE_ALIAS("platform:msm-slim");