blob: 2f198630238e3d42ee7bb6d31a584afe30c213f1 [file] [log] [blame]
Sagar Dharia33beca02012-10-22 16:21:46 -06001/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
Sagar Dharia71fcea52012-09-12 23:21:57 -06002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
Sagar Dharia71fcea52012-09-12 23:21:57 -060012#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>
19#include <linux/dma-mapping.h>
20#include <linux/slimbus/slimbus.h>
21#include <linux/delay.h>
22#include <linux/kthread.h>
23#include <linux/clk.h>
24#include <linux/pm_runtime.h>
25#include <linux/of.h>
26#include <linux/of_slimbus.h>
27#include <linux/timer.h>
28#include <mach/sps.h>
29#include "slim-msm.h"
30#include <mach/qdsp6v2/apr.h>
31
32#define NGD_SLIM_NAME "ngd_msm_ctrl"
33#define SLIM_LA_MGR 0xFF
34#define SLIM_ROOT_FREQ 24576000
Sagar Dharia33beca02012-10-22 16:21:46 -060035#define LADDR_RETRY 5
Sagar Dharia71fcea52012-09-12 23:21:57 -060036
37#define NGD_BASE_V1(r) (((r) % 2) ? 0x800 : 0xA00)
38#define NGD_BASE_V2(r) (((r) % 2) ? 0x1000 : 0x2000)
39#define NGD_BASE(r, v) ((v) ? NGD_BASE_V2(r) : NGD_BASE_V1(r))
40/* NGD (Non-ported Generic Device) registers */
41enum ngd_reg {
42 NGD_CFG = 0x0,
43 NGD_STATUS = 0x4,
44 NGD_RX_MSGQ_CFG = 0x8,
45 NGD_INT_EN = 0x10,
46 NGD_INT_STAT = 0x14,
47 NGD_INT_CLR = 0x18,
48 NGD_TX_MSG = 0x30,
49 NGD_RX_MSG = 0x70,
50 NGD_IE_STAT = 0xF0,
51 NGD_VE_STAT = 0x100,
52};
53
54enum ngd_msg_cfg {
55 NGD_CFG_ENABLE = 1,
56 NGD_CFG_RX_MSGQ_EN = 1 << 1,
57 NGD_CFG_TX_MSGQ_EN = 1 << 2,
58};
59
60enum ngd_intr {
61 NGD_INT_RECFG_DONE = 1 << 24,
62 NGD_INT_TX_NACKED_2 = 1 << 25,
63 NGD_INT_MSG_BUF_CONTE = 1 << 26,
64 NGD_INT_MSG_TX_INVAL = 1 << 27,
65 NGD_INT_IE_VE_CHG = 1 << 28,
66 NGD_INT_DEV_ERR = 1 << 29,
67 NGD_INT_RX_MSG_RCVD = 1 << 30,
68 NGD_INT_TX_MSG_SENT = 1 << 31,
69};
70
71enum ngd_offsets {
72 NGD_NACKED_MC = 0x7F00000,
73 NGD_ACKED_MC = 0xFE000,
74 NGD_ERROR = 0x1800,
75 NGD_MSGQ_SUPPORT = 0x400,
76 NGD_RX_MSGQ_TIME_OUT = 0x16,
77 NGD_ENUMERATED = 0x1,
78 NGD_TX_BUSY = 0x0,
79};
80
Sagar Dharia33beca02012-10-22 16:21:46 -060081enum ngd_status {
82 NGD_LADDR = 1 << 1,
83};
84
85static int ngd_slim_runtime_resume(struct device *device);
86
Sagar Dharia71fcea52012-09-12 23:21:57 -060087static irqreturn_t ngd_slim_interrupt(int irq, void *d)
88{
89 struct msm_slim_ctrl *dev = (struct msm_slim_ctrl *)d;
90 void __iomem *ngd = dev->base + NGD_BASE(dev->ctrl.nr, dev->ver);
91 u32 stat = readl_relaxed(ngd + NGD_INT_STAT);
Sagar Dharia2b8a4b52013-05-15 20:01:45 -060092 u32 pstat;
Sagar Dharia71fcea52012-09-12 23:21:57 -060093
94 if (stat & NGD_INT_TX_MSG_SENT) {
95 writel_relaxed(NGD_INT_TX_MSG_SENT, ngd + NGD_INT_CLR);
96 /* Make sure interrupt is cleared */
97 mb();
98 if (dev->wr_comp)
99 complete(dev->wr_comp);
100 } else if ((stat & NGD_INT_MSG_BUF_CONTE) ||
101 (stat & NGD_INT_MSG_TX_INVAL) || (stat & NGD_INT_DEV_ERR) ||
102 (stat & NGD_INT_TX_NACKED_2)) {
103 dev_err(dev->dev, "NGD interrupt error:0x%x", stat);
104 writel_relaxed(stat, ngd + NGD_INT_CLR);
105 /* Guarantee that error interrupts are cleared */
106 mb();
107 if (((stat & NGD_INT_TX_NACKED_2) ||
108 (stat & NGD_INT_MSG_TX_INVAL))) {
109 dev->err = -EIO;
110 if (dev->wr_comp)
111 complete(dev->wr_comp);
112 }
113 }
114 if (stat & NGD_INT_RX_MSG_RCVD) {
115 u32 rx_buf[10];
116 u8 len, i;
117 rx_buf[0] = readl_relaxed(ngd + NGD_RX_MSG);
118 len = rx_buf[0] & 0x1F;
119 for (i = 1; i < ((len + 3) >> 2); i++) {
120 rx_buf[i] = readl_relaxed(ngd + NGD_RX_MSG +
121 (4 * i));
122 dev_dbg(dev->dev, "REG-RX data: %x\n", rx_buf[i]);
123 }
124 msm_slim_rx_enqueue(dev, rx_buf, len);
125 writel_relaxed(NGD_INT_RX_MSG_RCVD,
126 ngd + NGD_INT_CLR);
127 /*
128 * Guarantee that CLR bit write goes through before
129 * queuing work
130 */
131 mb();
Sagar Dharia24419e32013-01-14 17:56:32 -0700132 if (dev->use_rx_msgqs == MSM_MSGQ_ENABLED)
Sagar Dharia71fcea52012-09-12 23:21:57 -0600133 dev_err(dev->dev,
134 "direct message received even with RX MSGQs");
135 else
136 complete(&dev->rx_msgq_notify);
137 }
138 if (stat & NGD_INT_RECFG_DONE) {
139 writel_relaxed(NGD_INT_RECFG_DONE, ngd + NGD_INT_CLR);
140 /* Guarantee RECONFIG DONE interrupt is cleared */
141 mb();
142 /* In satellite mode, just log the reconfig done IRQ */
143 dev_dbg(dev->dev, "reconfig done IRQ for NGD");
144 }
145 if (stat & NGD_INT_IE_VE_CHG) {
146 writel_relaxed(NGD_INT_IE_VE_CHG, ngd + NGD_INT_CLR);
147 /* Guarantee IE VE change interrupt is cleared */
148 mb();
149 dev_err(dev->dev, "NGD IE VE change");
150 }
Sagar Dharia2b8a4b52013-05-15 20:01:45 -0600151
152 pstat = readl_relaxed(PGD_THIS_EE(PGD_PORT_INT_ST_EEn, dev->ver));
153 if (pstat != 0)
154 return msm_slim_port_irq_handler(dev, pstat);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600155 return IRQ_HANDLED;
156}
157
Sagar Dhariacc1001e2012-11-06 13:56:42 -0700158static int ngd_qmi_available(struct notifier_block *n, unsigned long code,
159 void *_cmd)
160{
161 struct msm_slim_qmi *qmi = container_of(n, struct msm_slim_qmi, nb);
Sagar Dharia33beca02012-10-22 16:21:46 -0600162 struct msm_slim_ctrl *dev =
163 container_of(qmi, struct msm_slim_ctrl, qmi);
Sagar Dhariacc1001e2012-11-06 13:56:42 -0700164 pr_info("Slimbus QMI NGD CB received event:%ld", code);
165 switch (code) {
166 case QMI_SERVER_ARRIVE:
Sagar Dharia33beca02012-10-22 16:21:46 -0600167 schedule_work(&qmi->ssr_up);
Sagar Dhariacc1001e2012-11-06 13:56:42 -0700168 break;
169 case QMI_SERVER_EXIT:
Sagar Dharia33beca02012-10-22 16:21:46 -0600170 dev->state = MSM_CTRL_DOWN;
171 /* make sure autosuspend is not called until ADSP comes up*/
172 pm_runtime_get_noresume(dev->dev);
173 /* Reset ctrl_up completion */
174 init_completion(&dev->ctrl_up);
175 schedule_work(&qmi->ssr_down);
Sagar Dhariacc1001e2012-11-06 13:56:42 -0700176 break;
177 default:
178 break;
179 }
180 return 0;
181}
182
Sagar Dharia71fcea52012-09-12 23:21:57 -0600183static int ngd_get_tid(struct slim_controller *ctrl, struct slim_msg_txn *txn,
184 u8 *tid, struct completion *done)
185{
186 struct msm_slim_ctrl *dev = slim_get_ctrldata(ctrl);
Sagar Dhariad2959352012-12-01 15:43:01 -0700187 mutex_lock(&ctrl->m_ctrl);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600188 if (ctrl->last_tid <= 255) {
189 ctrl->txnt = krealloc(ctrl->txnt,
190 (ctrl->last_tid + 1) *
191 sizeof(struct slim_msg_txn *),
192 GFP_KERNEL);
Sagar Dhariad2959352012-12-01 15:43:01 -0700193 if (!ctrl->txnt) {
194 mutex_unlock(&ctrl->m_ctrl);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600195 return -ENOMEM;
Sagar Dhariad2959352012-12-01 15:43:01 -0700196 }
Sagar Dharia71fcea52012-09-12 23:21:57 -0600197 dev->msg_cnt = ctrl->last_tid;
198 ctrl->last_tid++;
199 } else {
200 int i;
201 for (i = 0; i < 256; i++) {
202 dev->msg_cnt = ((dev->msg_cnt + 1) & 0xFF);
203 if (ctrl->txnt[dev->msg_cnt] == NULL)
204 break;
205 }
206 if (i >= 256) {
207 dev_err(&ctrl->dev, "out of TID");
Sagar Dhariad2959352012-12-01 15:43:01 -0700208 mutex_unlock(&ctrl->m_ctrl);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600209 return -ENOMEM;
210 }
211 }
212 ctrl->txnt[dev->msg_cnt] = txn;
213 txn->tid = dev->msg_cnt;
214 txn->comp = done;
215 *tid = dev->msg_cnt;
Sagar Dhariad2959352012-12-01 15:43:01 -0700216 mutex_unlock(&ctrl->m_ctrl);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600217 return 0;
218}
219static int ngd_xfer_msg(struct slim_controller *ctrl, struct slim_msg_txn *txn)
220{
221 DECLARE_COMPLETION_ONSTACK(done);
222 DECLARE_COMPLETION_ONSTACK(tx_sent);
223
224 struct msm_slim_ctrl *dev = slim_get_ctrldata(ctrl);
225 u32 *pbuf;
226 u8 *puc;
227 int ret = 0;
Sagar Dharia71fcea52012-09-12 23:21:57 -0600228 u8 la = txn->la;
Sagar Dharia5c8ad192013-05-31 11:39:05 -0600229 u8 wbuf[SLIM_MSGQ_BUF_LEN];
Sagar Dharia71fcea52012-09-12 23:21:57 -0600230
Sagar Dhariaa1398282013-01-22 13:26:20 -0700231 if (!pm_runtime_enabled(dev->dev) && dev->state == MSM_CTRL_ASLEEP &&
232 txn->mc != SLIM_USR_MC_REPORT_SATELLITE) {
233 /*
234 * Counter-part of system-suspend when runtime-pm is not enabled
235 * This way, resume can be left empty and device will be put in
236 * active mode only if client requests anything on the bus
237 * If the state was DOWN, SSR UP notification will take
238 * care of putting the device in active state.
239 */
240 ngd_slim_runtime_resume(dev->dev);
241 }
Sagar Dharia5c8ad192013-05-31 11:39:05 -0600242 if ((txn->mc == (SLIM_MSG_CLK_PAUSE_SEQ_FLG |
243 SLIM_MSG_MC_RECONFIGURE_NOW)) &&
244 dev->state <= MSM_CTRL_SLEEPING) {
245 msm_slim_disconnect_endp(dev, &dev->rx_msgq,
246 &dev->use_rx_msgqs);
247 msm_slim_disconnect_endp(dev, &dev->tx_msgq,
248 &dev->use_tx_msgqs);
249 return msm_slim_qmi_power_request(dev, false);
Sagar Dharia24419e32013-01-14 17:56:32 -0700250 }
Sagar Dhariacc1001e2012-11-06 13:56:42 -0700251 else if (txn->mc & SLIM_MSG_CLK_PAUSE_SEQ_FLG)
252 return 0;
253
Sagar Dharia71fcea52012-09-12 23:21:57 -0600254 if (txn->mt == SLIM_MSG_MT_CORE &&
255 (txn->mc >= SLIM_MSG_MC_BEGIN_RECONFIGURATION &&
256 txn->mc <= SLIM_MSG_MC_RECONFIGURE_NOW)) {
257 return 0;
258 }
Sagar Dharia33beca02012-10-22 16:21:46 -0600259 /* If txn is tried when controller is down, wait for ADSP to boot */
260 if (txn->mc != SLIM_USR_MC_REPORT_SATELLITE) {
261 if (dev->state == MSM_CTRL_DOWN) {
262 u8 mc = (u8)txn->mc;
263 int timeout;
264 dev_err(dev->dev, "ADSP slimbus not up yet");
265 /*
266 * Messages related to data channel management can't
267 * wait since they are holding reconfiguration lock.
268 * clk_pause in resume (which can change state back to
269 * MSM_CTRL_AWAKE), will need that lock
270 */
271 if ((txn->mt == SLIM_MSG_MT_CORE) &&
272 ((mc >= SLIM_MSG_MC_CONNECT_SOURCE &&
273 mc <= SLIM_MSG_MC_CHANGE_CONTENT) ||
274 (mc >= SLIM_MSG_MC_BEGIN_RECONFIGURATION &&
275 mc <= SLIM_MSG_MC_RECONFIGURE_NOW)))
276 return -EREMOTEIO;
277 if ((txn->mt == SLIM_MSG_MT_DEST_REFERRED_USER) &&
278 ((mc >= SLIM_USR_MC_DEFINE_CHAN &&
279 mc <= SLIM_USR_MC_DISCONNECT_PORT)))
280 return -EREMOTEIO;
281 timeout = wait_for_completion_timeout(&dev->ctrl_up,
282 HZ);
283 if (!timeout)
284 return -ETIMEDOUT;
285 }
286 msm_slim_get_ctrl(dev);
287 }
Sagar Dharia71fcea52012-09-12 23:21:57 -0600288 mutex_lock(&dev->tx_lock);
Sagar Dharia33beca02012-10-22 16:21:46 -0600289
Sagar Dharia71fcea52012-09-12 23:21:57 -0600290 if (txn->mc != SLIM_USR_MC_REPORT_SATELLITE &&
Sagar Dharia33beca02012-10-22 16:21:46 -0600291 (dev->state != MSM_CTRL_AWAKE)) {
Sagar Dharia71fcea52012-09-12 23:21:57 -0600292 dev_err(dev->dev, "controller not ready");
293 mutex_unlock(&dev->tx_lock);
Sagar Dharia33beca02012-10-22 16:21:46 -0600294 msm_slim_put_ctrl(dev);
295 return -EREMOTEIO;
Sagar Dharia71fcea52012-09-12 23:21:57 -0600296 }
297 if (txn->mt == SLIM_MSG_MT_CORE &&
298 (txn->mc == SLIM_MSG_MC_CONNECT_SOURCE ||
299 txn->mc == SLIM_MSG_MC_CONNECT_SINK ||
300 txn->mc == SLIM_MSG_MC_DISCONNECT_PORT)) {
301 int i = 0;
302 txn->mt = SLIM_MSG_MT_DEST_REFERRED_USER;
303 if (txn->mc == SLIM_MSG_MC_CONNECT_SOURCE)
304 txn->mc = SLIM_USR_MC_CONNECT_SRC;
305 else if (txn->mc == SLIM_MSG_MC_CONNECT_SINK)
306 txn->mc = SLIM_USR_MC_CONNECT_SINK;
307 else if (txn->mc == SLIM_MSG_MC_DISCONNECT_PORT)
308 txn->mc = SLIM_USR_MC_DISCONNECT_PORT;
Sagar Dhariaa3c6a382013-06-21 12:18:20 -0600309 if (txn->la == SLIM_LA_MGR) {
310 if (dev->pgdla == SLIM_LA_MGR) {
311 u8 ea[] = {0, QC_DEVID_PGD, 0, 0, QC_MFGID_MSB,
312 QC_MFGID_LSB};
313 ea[2] = (u8)(dev->pdata.eapc & 0xFF);
314 ea[3] = (u8)((dev->pdata.eapc & 0xFF00) >> 8);
315 mutex_unlock(&dev->tx_lock);
316 ret = dev->ctrl.get_laddr(&dev->ctrl, ea, 6,
317 &dev->pgdla);
318 pr_debug("SLIM PGD LA:0x%x, ret:%d", dev->pgdla,
319 ret);
320 if (ret) {
321 pr_err("Incorrect SLIM-PGD EAPC:0x%x",
322 dev->pdata.eapc);
323 return ret;
324 }
325 mutex_lock(&dev->tx_lock);
326 }
Sagar Dharia71fcea52012-09-12 23:21:57 -0600327 txn->la = dev->pgdla;
Sagar Dhariaa3c6a382013-06-21 12:18:20 -0600328 }
Sagar Dharia71fcea52012-09-12 23:21:57 -0600329 wbuf[i++] = txn->la;
330 la = SLIM_LA_MGR;
331 wbuf[i++] = txn->wbuf[0];
332 if (txn->mc != SLIM_USR_MC_DISCONNECT_PORT)
333 wbuf[i++] = txn->wbuf[1];
334 ret = ngd_get_tid(ctrl, txn, &wbuf[i++], &done);
335 if (ret) {
336 pr_err("TID for connect/disconnect fail:%d", ret);
337 goto ngd_xfer_err;
338 }
339 txn->len = i;
340 txn->wbuf = wbuf;
341 txn->rl = txn->len + 4;
342 }
343 txn->rl--;
344 pbuf = msm_get_msg_buf(dev, txn->rl);
345 if (!pbuf) {
346 dev_err(dev->dev, "Message buffer unavailable");
347 ret = -ENOMEM;
348 goto ngd_xfer_err;
349 }
350 dev->err = 0;
351
352 if (txn->dt == SLIM_MSG_DEST_ENUMADDR) {
353 ret = -EPROTONOSUPPORT;
354 goto ngd_xfer_err;
355 }
356 if (txn->dt == SLIM_MSG_DEST_LOGICALADDR)
357 *pbuf = SLIM_MSG_ASM_FIRST_WORD(txn->rl, txn->mt, txn->mc, 0,
358 la);
359 else
360 *pbuf = SLIM_MSG_ASM_FIRST_WORD(txn->rl, txn->mt, txn->mc, 1,
361 la);
362 if (txn->dt == SLIM_MSG_DEST_LOGICALADDR)
363 puc = ((u8 *)pbuf) + 3;
364 else
365 puc = ((u8 *)pbuf) + 2;
366 if (txn->rbuf)
367 *(puc++) = txn->tid;
368 if ((txn->mt == SLIM_MSG_MT_CORE) &&
369 ((txn->mc >= SLIM_MSG_MC_REQUEST_INFORMATION &&
370 txn->mc <= SLIM_MSG_MC_REPORT_INFORMATION) ||
371 (txn->mc >= SLIM_MSG_MC_REQUEST_VALUE &&
372 txn->mc <= SLIM_MSG_MC_CHANGE_VALUE))) {
373 *(puc++) = (txn->ec & 0xFF);
374 *(puc++) = (txn->ec >> 8)&0xFF;
375 }
376 if (txn->wbuf)
377 memcpy(puc, txn->wbuf, txn->len);
378 if (txn->mt == SLIM_MSG_MT_DEST_REFERRED_USER &&
379 (txn->mc == SLIM_USR_MC_CONNECT_SRC ||
380 txn->mc == SLIM_USR_MC_CONNECT_SINK ||
381 txn->mc == SLIM_USR_MC_DISCONNECT_PORT) && txn->wbuf &&
382 wbuf[0] == dev->pgdla) {
Sagar Dharia2d74c142013-05-17 02:24:06 -0600383 if (txn->mc != SLIM_USR_MC_DISCONNECT_PORT)
Sagar Dharia71fcea52012-09-12 23:21:57 -0600384 dev->err = msm_slim_connect_pipe_port(dev, wbuf[1]);
385 else {
Sagar Dharia71fcea52012-09-12 23:21:57 -0600386 /*
387 * Remove channel disconnects master-side ports from
388 * channel. No need to send that again on the bus
Sagar Dharia2d74c142013-05-17 02:24:06 -0600389 * Only disable port
Sagar Dharia71fcea52012-09-12 23:21:57 -0600390 */
Sagar Dharia2d74c142013-05-17 02:24:06 -0600391 writel_relaxed(0, PGD_PORT(PGD_PORT_CFGn,
392 (wbuf[1] + dev->port_b), dev->ver));
Sagar Dharia71fcea52012-09-12 23:21:57 -0600393 mutex_unlock(&dev->tx_lock);
Sagar Dhariacc1001e2012-11-06 13:56:42 -0700394 msm_slim_put_ctrl(dev);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600395 return 0;
396 }
397 if (dev->err) {
398 dev_err(dev->dev, "pipe-port connect err:%d", dev->err);
399 goto ngd_xfer_err;
400 }
Sagar Dhariaa3c6a382013-06-21 12:18:20 -0600401 /* Add port-base to port number if this is manager side port */
402 puc[1] += dev->port_b;
Sagar Dharia71fcea52012-09-12 23:21:57 -0600403 }
404 dev->err = 0;
405 dev->wr_comp = &tx_sent;
406 ret = msm_send_msg_buf(dev, pbuf, txn->rl,
407 NGD_BASE(dev->ctrl.nr, dev->ver) + NGD_TX_MSG);
408 if (!ret) {
409 int timeout = wait_for_completion_timeout(&tx_sent, HZ);
Sagar Dharia5c8ad192013-05-31 11:39:05 -0600410 if (!timeout) {
Sagar Dharia71fcea52012-09-12 23:21:57 -0600411 ret = -ETIMEDOUT;
Sagar Dharia5c8ad192013-05-31 11:39:05 -0600412 /*
413 * disconnect/recoonect pipe so that subsequent
414 * transactions don't timeout due to unavailable
415 * descriptors
416 */
417 msm_slim_disconnect_endp(dev, &dev->tx_msgq,
418 &dev->use_tx_msgqs);
419 msm_slim_connect_endp(dev, &dev->tx_msgq, NULL);
420 } else {
Sagar Dharia71fcea52012-09-12 23:21:57 -0600421 ret = dev->err;
Sagar Dharia5c8ad192013-05-31 11:39:05 -0600422 }
Sagar Dharia71fcea52012-09-12 23:21:57 -0600423 }
424 dev->wr_comp = NULL;
425 if (ret) {
426 u32 conf, stat, rx_msgq, int_stat, int_en, int_clr;
427 void __iomem *ngd = dev->base + NGD_BASE(dev->ctrl.nr,
428 dev->ver);
429 dev_err(dev->dev, "TX failed :MC:0x%x,mt:0x%x, ret:%d, ver:%d",
430 txn->mc, txn->mt, ret, dev->ver);
431 conf = readl_relaxed(ngd);
432 stat = readl_relaxed(ngd + NGD_STATUS);
433 rx_msgq = readl_relaxed(ngd + NGD_RX_MSGQ_CFG);
434 int_stat = readl_relaxed(ngd + NGD_INT_STAT);
435 int_en = readl_relaxed(ngd + NGD_INT_EN);
436 int_clr = readl_relaxed(ngd + NGD_INT_CLR);
437
438 pr_err("conf:0x%x,stat:0x%x,rxmsgq:0x%x", conf, stat, rx_msgq);
439 pr_err("int_stat:0x%x,int_en:0x%x,int_cll:0x%x", int_stat,
440 int_en, int_clr);
441 } else if (txn->mt == SLIM_MSG_MT_DEST_REFERRED_USER &&
442 (txn->mc == SLIM_USR_MC_CONNECT_SRC ||
443 txn->mc == SLIM_USR_MC_CONNECT_SINK ||
444 txn->mc == SLIM_USR_MC_DISCONNECT_PORT)) {
445 int timeout;
446 mutex_unlock(&dev->tx_lock);
Sagar Dhariacc1001e2012-11-06 13:56:42 -0700447 msm_slim_put_ctrl(dev);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600448 timeout = wait_for_completion_timeout(txn->comp, HZ);
Sagar Dharia33beca02012-10-22 16:21:46 -0600449 if (!timeout)
Sagar Dharia71fcea52012-09-12 23:21:57 -0600450 ret = -ETIMEDOUT;
Sagar Dharia33beca02012-10-22 16:21:46 -0600451 else
452 ret = txn->ec;
453 if (ret) {
454 pr_err("connect/disconnect:0x%x,tid:%d err:%d", txn->mc,
455 txn->tid, ret);
Sagar Dhariad2959352012-12-01 15:43:01 -0700456 mutex_lock(&ctrl->m_ctrl);
457 ctrl->txnt[txn->tid] = NULL;
458 mutex_unlock(&ctrl->m_ctrl);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600459 }
Sagar Dharia71fcea52012-09-12 23:21:57 -0600460 return ret ? ret : dev->err;
461 }
462ngd_xfer_err:
463 mutex_unlock(&dev->tx_lock);
Sagar Dharia33beca02012-10-22 16:21:46 -0600464 if (txn->mc != SLIM_USR_MC_REPORT_SATELLITE)
465 msm_slim_put_ctrl(dev);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600466 return ret ? ret : dev->err;
467}
468
469static int ngd_xferandwait_ack(struct slim_controller *ctrl,
470 struct slim_msg_txn *txn)
471{
472 int ret = ngd_xfer_msg(ctrl, txn);
473 if (!ret) {
474 int timeout;
475 timeout = wait_for_completion_timeout(txn->comp, HZ);
Sagar Dharia33beca02012-10-22 16:21:46 -0600476 if (!timeout)
Sagar Dharia71fcea52012-09-12 23:21:57 -0600477 ret = -ETIMEDOUT;
Sagar Dharia33beca02012-10-22 16:21:46 -0600478 else
Sagar Dharia71fcea52012-09-12 23:21:57 -0600479 ret = txn->ec;
Sagar Dharia71fcea52012-09-12 23:21:57 -0600480 }
Sagar Dharia33beca02012-10-22 16:21:46 -0600481 if (ret) {
Sagar Dharia71fcea52012-09-12 23:21:57 -0600482 pr_err("master msg:0x%x,tid:%d ret:%d", txn->mc,
483 txn->tid, ret);
Sagar Dharia33beca02012-10-22 16:21:46 -0600484 mutex_lock(&ctrl->m_ctrl);
485 ctrl->txnt[txn->tid] = NULL;
486 mutex_unlock(&ctrl->m_ctrl);
487 }
Sagar Dharia71fcea52012-09-12 23:21:57 -0600488
489 return ret;
490}
491
492static int ngd_allocbw(struct slim_device *sb, int *subfrmc, int *clkgear)
493{
494 int ret;
495 struct slim_pending_ch *pch;
496 struct slim_msg_txn txn;
497 struct slim_controller *ctrl = sb->ctrl;
498 DECLARE_COMPLETION_ONSTACK(done);
Sagar Dharia5c8ad192013-05-31 11:39:05 -0600499 u8 wbuf[SLIM_MSGQ_BUF_LEN];
Sagar Dharia71fcea52012-09-12 23:21:57 -0600500
Sagar Dharia5ee34ae2013-04-26 18:05:37 -0600501 *clkgear = ctrl->clkgear;
502 *subfrmc = 0;
Sagar Dharia71fcea52012-09-12 23:21:57 -0600503 txn.mt = SLIM_MSG_MT_DEST_REFERRED_USER;
504 txn.dt = SLIM_MSG_DEST_LOGICALADDR;
505 txn.la = SLIM_LA_MGR;
506 txn.len = 0;
507 txn.ec = 0;
508 txn.wbuf = wbuf;
509 txn.rbuf = NULL;
510
Sagar Dharia5ee34ae2013-04-26 18:05:37 -0600511 if (ctrl->sched.msgsl != ctrl->sched.pending_msgsl) {
512 pr_debug("slim reserve BW for messaging: req: %d",
513 ctrl->sched.pending_msgsl);
514 txn.mc = SLIM_USR_MC_REQ_BW;
515 wbuf[txn.len++] = ((sb->laddr & 0x1f) |
516 ((u8)(ctrl->sched.pending_msgsl & 0x7) << 5));
517 wbuf[txn.len++] = (u8)(ctrl->sched.pending_msgsl >> 3);
518 ret = ngd_get_tid(ctrl, &txn, &wbuf[txn.len++], &done);
519 if (ret)
520 return ret;
521 txn.rl = txn.len + 4;
522 ret = ngd_xferandwait_ack(ctrl, &txn);
523 if (ret)
524 return ret;
525
526 txn.mc = SLIM_USR_MC_RECONFIG_NOW;
527 txn.len = 2;
528 wbuf[1] = sb->laddr;
529 txn.rl = txn.len + 4;
530 ret = ngd_get_tid(ctrl, &txn, &wbuf[0], &done);
531 if (ret)
532 return ret;
533 ret = ngd_xferandwait_ack(ctrl, &txn);
534 if (ret)
535 return ret;
536
537 txn.len = 0;
538 }
Sagar Dharia71fcea52012-09-12 23:21:57 -0600539 list_for_each_entry(pch, &sb->mark_define, pending) {
540 struct slim_ich *slc;
541 slc = &ctrl->chans[pch->chan];
542 if (!slc) {
543 pr_err("no channel in define?");
544 return -ENXIO;
545 }
546 if (txn.len == 0) {
Sagar Dhariab47c8962012-10-30 13:44:08 -0600547 /* Per protocol, only last 5 bits for client no. */
Sagar Dharia71fcea52012-09-12 23:21:57 -0600548 wbuf[txn.len++] = (u8) (slc->prop.dataf << 5) |
Sagar Dhariab47c8962012-10-30 13:44:08 -0600549 (sb->laddr & 0x1f);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600550 wbuf[txn.len] = slc->seglen;
551 if (slc->coeff == SLIM_COEFF_3)
552 wbuf[txn.len] |= 1 << 5;
553 wbuf[txn.len++] |= slc->prop.auxf << 6;
554 wbuf[txn.len++] = slc->rootexp << 4 | slc->prop.prot;
555 wbuf[txn.len++] = slc->prrate;
556 ret = ngd_get_tid(ctrl, &txn, &wbuf[txn.len++], &done);
557 if (ret) {
558 pr_err("no tid for channel define?");
559 return -ENXIO;
560 }
561 }
562 wbuf[txn.len++] = slc->chan;
Sagar Dhariab47c8962012-10-30 13:44:08 -0600563 pr_debug("slim define chan:%d, tid:0x%x", slc->chan, txn.tid);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600564 }
565 if (txn.len) {
566 txn.mc = SLIM_USR_MC_DEF_ACT_CHAN;
567 txn.rl = txn.len + 4;
568 ret = ngd_xferandwait_ack(ctrl, &txn);
569 if (ret)
570 return ret;
571
572 txn.mc = SLIM_USR_MC_RECONFIG_NOW;
573 txn.len = 2;
574 wbuf[1] = sb->laddr;
575 txn.rl = txn.len + 4;
576 ret = ngd_get_tid(ctrl, &txn, &wbuf[0], &done);
577 if (ret)
578 return ret;
579 ret = ngd_xferandwait_ack(ctrl, &txn);
580 if (ret)
581 return ret;
582 }
583 txn.len = 0;
584 list_for_each_entry(pch, &sb->mark_removal, pending) {
585 struct slim_ich *slc;
586 slc = &ctrl->chans[pch->chan];
587 if (!slc) {
588 pr_err("no channel in removal?");
589 return -ENXIO;
590 }
591 if (txn.len == 0) {
Sagar Dhariab47c8962012-10-30 13:44:08 -0600592 /* Per protocol, only last 5 bits for client no. */
Sagar Dharia71fcea52012-09-12 23:21:57 -0600593 wbuf[txn.len++] = (u8) (SLIM_CH_REMOVE << 6) |
Sagar Dhariab47c8962012-10-30 13:44:08 -0600594 (sb->laddr & 0x1f);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600595 ret = ngd_get_tid(ctrl, &txn, &wbuf[txn.len++], &done);
596 if (ret) {
597 pr_err("no tid for channel define?");
598 return -ENXIO;
599 }
600 }
601 wbuf[txn.len++] = slc->chan;
Sagar Dhariab47c8962012-10-30 13:44:08 -0600602 pr_debug("slim remove chan:%d, tid:0x%x", slc->chan, txn.tid);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600603 }
604 if (txn.len) {
605 txn.mc = SLIM_USR_MC_CHAN_CTRL;
606 txn.rl = txn.len + 4;
607 ret = ngd_xferandwait_ack(ctrl, &txn);
608 if (ret)
609 return ret;
610
611 txn.mc = SLIM_USR_MC_RECONFIG_NOW;
612 txn.len = 2;
613 wbuf[1] = sb->laddr;
614 txn.rl = txn.len + 4;
615 ret = ngd_get_tid(ctrl, &txn, &wbuf[0], &done);
616 if (ret)
617 return ret;
618 ret = ngd_xferandwait_ack(ctrl, &txn);
619 if (ret)
620 return ret;
621 txn.len = 0;
622 }
Sagar Dharia24419e32013-01-14 17:56:32 -0700623 return 0;
Sagar Dharia71fcea52012-09-12 23:21:57 -0600624}
625
626static int ngd_set_laddr(struct slim_controller *ctrl, const u8 *ea,
627 u8 elen, u8 laddr)
628{
629 return 0;
630}
631
632static int ngd_get_laddr(struct slim_controller *ctrl, const u8 *ea,
633 u8 elen, u8 *laddr)
634{
635 int ret;
636 u8 wbuf[10];
637 struct slim_msg_txn txn;
638 DECLARE_COMPLETION_ONSTACK(done);
639 txn.mt = SLIM_MSG_MT_DEST_REFERRED_USER;
640 txn.dt = SLIM_MSG_DEST_LOGICALADDR;
641 txn.la = SLIM_LA_MGR;
642 txn.ec = 0;
Sagar Dharia71fcea52012-09-12 23:21:57 -0600643 ret = ngd_get_tid(ctrl, &txn, &wbuf[0], &done);
644 if (ret) {
Sagar Dharia71fcea52012-09-12 23:21:57 -0600645 return ret;
646 }
647 memcpy(&wbuf[1], ea, elen);
648 txn.mc = SLIM_USR_MC_ADDR_QUERY;
649 txn.rl = 11;
650 txn.len = 7;
651 txn.wbuf = wbuf;
652 txn.rbuf = NULL;
653 ret = ngd_xferandwait_ack(ctrl, &txn);
654 if (!ret && txn.la == 0xFF)
655 ret = -ENXIO;
656 else if (!ret)
657 *laddr = txn.la;
Sagar Dharia71fcea52012-09-12 23:21:57 -0600658 return ret;
659}
660
Sagar Dharia5c8ad192013-05-31 11:39:05 -0600661static void ngd_slim_setup_msg_path(struct msm_slim_ctrl *dev)
Sagar Dharia24419e32013-01-14 17:56:32 -0700662{
Sagar Dharia24419e32013-01-14 17:56:32 -0700663 if (dev->state == MSM_CTRL_DOWN) {
664 msm_slim_sps_init(dev, dev->bam_mem,
665 NGD_BASE(dev->ctrl.nr,
666 dev->ver) + NGD_STATUS, true);
667 } else {
668 if (dev->use_rx_msgqs == MSM_MSGQ_DISABLED)
Sagar Dharia5c8ad192013-05-31 11:39:05 -0600669 goto setup_tx_msg_path;
670 msm_slim_connect_endp(dev, &dev->rx_msgq,
Sagar Dharia24419e32013-01-14 17:56:32 -0700671 &dev->rx_msgq_notify);
Sagar Dharia5c8ad192013-05-31 11:39:05 -0600672
673setup_tx_msg_path:
674 if (dev->use_tx_msgqs == MSM_MSGQ_DISABLED)
675 return;
676 msm_slim_connect_endp(dev, &dev->tx_msgq,
677 NULL);
Sagar Dharia24419e32013-01-14 17:56:32 -0700678 }
679}
Sagar Dharia5c8ad192013-05-31 11:39:05 -0600680
Sagar Dharia71fcea52012-09-12 23:21:57 -0600681static void ngd_slim_rx(struct msm_slim_ctrl *dev, u8 *buf)
682{
683 u8 mc, mt, len;
684 int ret;
685 u32 msgq_en = 1;
686
687 len = buf[0] & 0x1F;
688 mt = (buf[0] >> 5) & 0x7;
689 mc = buf[1];
690 if (mc == SLIM_USR_MC_MASTER_CAPABILITY &&
691 mt == SLIM_MSG_MT_SRC_REFERRED_USER) {
692 struct slim_msg_txn txn;
Sagar Dharia0a693332013-04-15 17:59:03 -0600693 int retries = 0;
Sagar Dharia71fcea52012-09-12 23:21:57 -0600694 u8 wbuf[8];
695 txn.dt = SLIM_MSG_DEST_LOGICALADDR;
696 txn.ec = 0;
697 txn.rbuf = NULL;
698 txn.mc = SLIM_USR_MC_REPORT_SATELLITE;
699 txn.mt = SLIM_MSG_MT_SRC_REFERRED_USER;
700 txn.la = SLIM_LA_MGR;
Sagar Dharia71fcea52012-09-12 23:21:57 -0600701 wbuf[0] = SAT_MAGIC_LSB;
702 wbuf[1] = SAT_MAGIC_MSB;
703 wbuf[2] = SAT_MSG_VER;
704 wbuf[3] = SAT_MSG_PROT;
705 txn.wbuf = wbuf;
706 txn.len = 4;
Sagar Dhariacc1001e2012-11-06 13:56:42 -0700707 pr_info("SLIM SAT: Received master capability");
Sagar Dharia24419e32013-01-14 17:56:32 -0700708 if (dev->state >= MSM_CTRL_ASLEEP) {
Sagar Dharia5c8ad192013-05-31 11:39:05 -0600709 ngd_slim_setup_msg_path(dev);
Sagar Dharia24419e32013-01-14 17:56:32 -0700710 if (dev->use_rx_msgqs == MSM_MSGQ_ENABLED)
Sagar Dharia33beca02012-10-22 16:21:46 -0600711 msgq_en |= NGD_CFG_RX_MSGQ_EN;
Sagar Dharia5c8ad192013-05-31 11:39:05 -0600712 if (dev->use_tx_msgqs == MSM_MSGQ_ENABLED)
713 msgq_en |= NGD_CFG_TX_MSGQ_EN;
Sagar Dharia33beca02012-10-22 16:21:46 -0600714 writel_relaxed(msgq_en, dev->base +
715 NGD_BASE(dev->ctrl.nr, dev->ver));
716 /* make sure NGD MSG-Q config goes through */
717 mb();
718 }
Sagar Dharia0a693332013-04-15 17:59:03 -0600719capability_retry:
720 txn.rl = 8;
Sagar Dharia71fcea52012-09-12 23:21:57 -0600721 ret = ngd_xfer_msg(&dev->ctrl, &txn);
722 if (!ret) {
Sagar Dharia33beca02012-10-22 16:21:46 -0600723 enum msm_ctrl_state prev_state = dev->state;
Sagar Dharia71fcea52012-09-12 23:21:57 -0600724 dev->state = MSM_CTRL_AWAKE;
Sagar Dharia33beca02012-10-22 16:21:46 -0600725 if (prev_state >= MSM_CTRL_ASLEEP)
726 complete(&dev->reconf);
727 else
728 pr_err("SLIM: unexpected capability, state:%d",
729 prev_state);
730 /* ADSP SSR, send device_up notifications */
731 if (prev_state == MSM_CTRL_DOWN)
732 schedule_work(&dev->slave_notify);
Sagar Dharia0a693332013-04-15 17:59:03 -0600733 } else if (ret == -EIO) {
734 pr_info("capability message NACKed, retrying");
735 if (retries < INIT_MX_RETRIES) {
736 msleep(DEF_RETRY_MS);
737 retries++;
738 goto capability_retry;
739 }
Sagar Dharia71fcea52012-09-12 23:21:57 -0600740 }
741 }
742 if (mc == SLIM_MSG_MC_REPLY_INFORMATION ||
743 mc == SLIM_MSG_MC_REPLY_VALUE) {
744 u8 tid = buf[3];
745 dev_dbg(dev->dev, "tid:%d, len:%d\n", tid, len);
746 slim_msg_response(&dev->ctrl, &buf[4], tid,
747 len - 4);
748 pm_runtime_mark_last_busy(dev->dev);
749 }
750 if (mc == SLIM_USR_MC_ADDR_REPLY &&
751 mt == SLIM_MSG_MT_SRC_REFERRED_USER) {
Sagar Dhariad2959352012-12-01 15:43:01 -0700752 struct slim_msg_txn *txn;
Sagar Dharia71fcea52012-09-12 23:21:57 -0600753 u8 failed_ea[6] = {0, 0, 0, 0, 0, 0};
Sagar Dhariad2959352012-12-01 15:43:01 -0700754 mutex_lock(&dev->ctrl.m_ctrl);
755 txn = dev->ctrl.txnt[buf[3]];
756 if (!txn) {
757 pr_err("LADDR response after timeout, tid:0x%x",
758 buf[3]);
759 mutex_unlock(&dev->ctrl.m_ctrl);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600760 return;
Sagar Dhariad2959352012-12-01 15:43:01 -0700761 }
Sagar Dharia71fcea52012-09-12 23:21:57 -0600762 if (memcmp(&buf[4], failed_ea, 6))
763 txn->la = buf[10];
764 dev->ctrl.txnt[buf[3]] = NULL;
Sagar Dhariad2959352012-12-01 15:43:01 -0700765 mutex_unlock(&dev->ctrl.m_ctrl);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600766 complete(txn->comp);
767 }
768 if (mc == SLIM_USR_MC_GENERIC_ACK &&
769 mt == SLIM_MSG_MT_SRC_REFERRED_USER) {
Sagar Dhariad2959352012-12-01 15:43:01 -0700770 struct slim_msg_txn *txn;
771 mutex_lock(&dev->ctrl.m_ctrl);
772 txn = dev->ctrl.txnt[buf[3]];
773 if (!txn) {
774 pr_err("ACK received after timeout, tid:0x%x",
775 buf[3]);
776 mutex_unlock(&dev->ctrl.m_ctrl);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600777 return;
Sagar Dhariad2959352012-12-01 15:43:01 -0700778 }
Sagar Dharia71fcea52012-09-12 23:21:57 -0600779 dev_dbg(dev->dev, "got response:tid:%d, response:0x%x",
780 (int)buf[3], buf[4]);
781 if (!(buf[4] & MSM_SAT_SUCCSS)) {
782 dev_err(dev->dev, "TID:%d, NACK code:0x%x", (int)buf[3],
783 buf[4]);
784 txn->ec = -EIO;
785 }
786 dev->ctrl.txnt[buf[3]] = NULL;
Sagar Dhariad2959352012-12-01 15:43:01 -0700787 mutex_unlock(&dev->ctrl.m_ctrl);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600788 complete(txn->comp);
789 }
790}
Sagar Dhariacc1001e2012-11-06 13:56:42 -0700791
Sagar Dharia33beca02012-10-22 16:21:46 -0600792static int ngd_slim_power_up(struct msm_slim_ctrl *dev)
Sagar Dhariacc1001e2012-11-06 13:56:42 -0700793{
Sagar Dharia33beca02012-10-22 16:21:46 -0600794 void __iomem *ngd;
795 int timeout, ret;
796 enum msm_ctrl_state cur_state = dev->state;
797 u32 laddr;
Sagar Dharia24419e32013-01-14 17:56:32 -0700798 u32 ngd_int = (NGD_INT_TX_NACKED_2 |
Sagar Dhariacc1001e2012-11-06 13:56:42 -0700799 NGD_INT_MSG_BUF_CONTE | NGD_INT_MSG_TX_INVAL |
800 NGD_INT_IE_VE_CHG | NGD_INT_DEV_ERR |
801 NGD_INT_TX_MSG_SENT | NGD_INT_RX_MSG_RCVD);
Sagar Dharia33beca02012-10-22 16:21:46 -0600802
803 if (cur_state == MSM_CTRL_DOWN) {
804 int timeout = wait_for_completion_timeout(&dev->qmi.qmi_comp,
805 HZ);
806 if (!timeout)
807 pr_err("slimbus QMI init timed out");
808 }
809
810 ret = msm_slim_qmi_power_request(dev, true);
811 if (ret) {
812 pr_err("SLIM QMI power request failed:%d", ret);
813 return ret;
814 }
815 if (!dev->ver) {
816 dev->ver = readl_relaxed(dev->base);
817 /* Version info in 16 MSbits */
818 dev->ver >>= 16;
819 }
820 ngd = dev->base + NGD_BASE(dev->ctrl.nr, dev->ver);
821 laddr = readl_relaxed(ngd + NGD_STATUS);
822 if (laddr & NGD_LADDR) {
Sagar Dhariacc1001e2012-11-06 13:56:42 -0700823 /*
Sagar Dharia33beca02012-10-22 16:21:46 -0600824 * ADSP power collapse case, where HW wasn't reset.
825 * Reconnect BAM pipes if disconnected
Sagar Dhariacc1001e2012-11-06 13:56:42 -0700826 */
Sagar Dharia5c8ad192013-05-31 11:39:05 -0600827 ngd_slim_setup_msg_path(dev);
Sagar Dharia33beca02012-10-22 16:21:46 -0600828 return 0;
829 } else if (cur_state != MSM_CTRL_DOWN) {
830 pr_info("ADSP P.C. CTRL state:%d NGD not enumerated:0x%x",
831 dev->state, laddr);
Sagar Dharia33beca02012-10-22 16:21:46 -0600832 }
Sagar Dhariada48bd62013-03-21 18:02:40 -0600833 /* ADSP SSR scenario, need to disconnect pipe before connecting */
834 if (dev->use_rx_msgqs == MSM_MSGQ_DOWN) {
835 struct msm_slim_endp *endpoint = &dev->rx_msgq;
836 sps_disconnect(endpoint->sps);
837 sps_free_endpoint(endpoint->sps);
838 dev->use_rx_msgqs = MSM_MSGQ_RESET;
839 }
Sagar Dharia5c8ad192013-05-31 11:39:05 -0600840 if (dev->use_tx_msgqs == MSM_MSGQ_DOWN) {
841 struct msm_slim_endp *endpoint = &dev->tx_msgq;
842 sps_disconnect(endpoint->sps);
843 sps_free_endpoint(endpoint->sps);
844 dev->use_tx_msgqs = MSM_MSGQ_RESET;
845 }
Sagar Dharia33beca02012-10-22 16:21:46 -0600846 /*
847 * ADSP power collapse case (OR SSR), where HW was reset
848 * BAM programming will happen when capability message is received
849 */
850 writel_relaxed(ngd_int, dev->base + NGD_INT_EN +
Sagar Dhariacc1001e2012-11-06 13:56:42 -0700851 NGD_BASE(dev->ctrl.nr, dev->ver));
Sagar Dharia33beca02012-10-22 16:21:46 -0600852 /*
853 * Enable NGD. Configure NGD in register acc. mode until master
854 * announcement is received
855 */
Sagar Dharia24419e32013-01-14 17:56:32 -0700856 writel_relaxed(1, dev->base + NGD_BASE(dev->ctrl.nr, dev->ver));
Sagar Dharia33beca02012-10-22 16:21:46 -0600857 /* make sure NGD enabling goes through */
858 mb();
859
860 timeout = wait_for_completion_timeout(&dev->reconf, HZ);
861 if (!timeout) {
862 pr_err("failed to received master capability");
863 return -ETIMEDOUT;
864 }
865 if (cur_state == MSM_CTRL_DOWN)
866 complete(&dev->ctrl_up);
867 return 0;
868}
869
870static int ngd_slim_enable(struct msm_slim_ctrl *dev, bool enable)
871{
872 int ret = 0;
873 if (enable) {
874 ret = msm_slim_qmi_init(dev, false);
875 /* controller state should be in sync with framework state */
876 if (!ret) {
877 ret = slim_ctrl_clk_pause(&dev->ctrl, false,
878 SLIM_CLK_UNSPECIFIED);
879 complete(&dev->qmi.qmi_comp);
880 /*
881 * Power-up won't be called if clock pause failed.
882 * This can happen if ADSP SSR happened when audio
883 * session is in progress. Framework will think that
884 * clock pause failed so no need to wakeup controller.
885 * Call power-up explicitly in that case, since slimbus
886 * HW needs to be powered-on to be in sync with
887 * framework state
888 */
889 if (ret)
890 ngd_slim_power_up(dev);
891 if (!pm_runtime_enabled(dev->dev) ||
892 !pm_runtime_suspended(dev->dev))
893 ngd_slim_runtime_resume(dev->dev);
894 else
895 pm_runtime_resume(dev->dev);
896 pm_runtime_mark_last_busy(dev->dev);
897 pm_runtime_put(dev->dev);
898 } else
899 dev_err(dev->dev, "qmi init fail, ret:%d, state:%d",
900 ret, dev->state);
901 } else {
Sagar Dhariacc1001e2012-11-06 13:56:42 -0700902 msm_slim_qmi_exit(dev);
903 }
904
Sagar Dharia33beca02012-10-22 16:21:46 -0600905 return ret;
906}
907
908static int ngd_clk_pause_wakeup(struct slim_controller *ctrl)
909{
910 struct msm_slim_ctrl *dev = slim_get_ctrldata(ctrl);
911 return ngd_slim_power_up(dev);
Sagar Dhariacc1001e2012-11-06 13:56:42 -0700912}
913
Sagar Dharia71fcea52012-09-12 23:21:57 -0600914static int ngd_slim_rx_msgq_thread(void *data)
915{
916 struct msm_slim_ctrl *dev = (struct msm_slim_ctrl *)data;
917 struct completion *notify = &dev->rx_msgq_notify;
918 int ret = 0, index = 0;
919 u32 mc = 0;
920 u32 mt = 0;
921 u32 buffer[10];
922 u8 msg_len = 0;
923
924 while (!kthread_should_stop()) {
925 set_current_state(TASK_INTERRUPTIBLE);
926 ret = wait_for_completion_interruptible(notify);
927 if (ret) {
928 dev_err(dev->dev, "rx thread wait err:%d", ret);
929 continue;
930 }
931 /* 1 irq notification per message */
Sagar Dharia24419e32013-01-14 17:56:32 -0700932 if (dev->use_rx_msgqs != MSM_MSGQ_ENABLED) {
Sagar Dharia71fcea52012-09-12 23:21:57 -0600933 msm_slim_rx_dequeue(dev, (u8 *)buffer);
934 ngd_slim_rx(dev, (u8 *)buffer);
935 continue;
936 }
937 ret = msm_slim_rx_msgq_get(dev, buffer, index);
938 if (ret) {
939 dev_err(dev->dev, "rx_msgq_get() failed 0x%x\n", ret);
940 continue;
941 }
942
943 /* Wait for complete message */
944 if (index++ == 0) {
945 msg_len = *buffer & 0x1F;
946 mt = (buffer[0] >> 5) & 0x7;
947 mc = (buffer[0] >> 8) & 0xff;
948 dev_dbg(dev->dev, "MC: %x, MT: %x\n", mc, mt);
949 }
950 if ((index * 4) >= msg_len) {
951 index = 0;
952 ngd_slim_rx(dev, (u8 *)buffer);
953 } else
954 continue;
955 }
956 return 0;
957}
958
Sagar Dharia33beca02012-10-22 16:21:46 -0600959static void ngd_laddr_lookup(struct work_struct *work)
960{
961 struct msm_slim_ctrl *dev =
962 container_of(work, struct msm_slim_ctrl, slave_notify);
963 struct slim_controller *ctrl = &dev->ctrl;
964 struct slim_device *sbdev;
965 int i;
966 mutex_lock(&ctrl->m_ctrl);
967 list_for_each_entry(sbdev, &ctrl->devs, dev_list) {
968 int ret = 0;
969 mutex_unlock(&ctrl->m_ctrl);
970 for (i = 0; i < LADDR_RETRY; i++) {
971 ret = slim_get_logical_addr(sbdev, sbdev->e_addr,
972 6, &sbdev->laddr);
973 if (!ret)
974 break;
975 else /* time for ADSP to assign LA */
976 msleep(20);
977 }
978 mutex_lock(&ctrl->m_ctrl);
979 }
980 mutex_unlock(&ctrl->m_ctrl);
981}
982
983static void ngd_adsp_down(struct work_struct *work)
984{
985 struct msm_slim_qmi *qmi =
986 container_of(work, struct msm_slim_qmi, ssr_down);
987 struct msm_slim_ctrl *dev =
988 container_of(qmi, struct msm_slim_ctrl, qmi);
989 struct slim_controller *ctrl = &dev->ctrl;
990 struct slim_device *sbdev;
991 int i;
992
993 ngd_slim_enable(dev, false);
994 /* disconnect BAM pipes */
Sagar Dhariada48bd62013-03-21 18:02:40 -0600995 if (dev->use_rx_msgqs == MSM_MSGQ_ENABLED)
996 dev->use_rx_msgqs = MSM_MSGQ_DOWN;
Sagar Dharia5c8ad192013-05-31 11:39:05 -0600997 if (dev->use_tx_msgqs == MSM_MSGQ_ENABLED)
998 dev->use_tx_msgqs = MSM_MSGQ_DOWN;
Sagar Dharia33beca02012-10-22 16:21:46 -0600999 msm_slim_sps_exit(dev, false);
Sagar Dharia33beca02012-10-22 16:21:46 -06001000 mutex_lock(&ctrl->m_ctrl);
1001 /* device up should be called again after SSR */
1002 list_for_each_entry(sbdev, &ctrl->devs, dev_list)
1003 sbdev->notified = false;
1004 /* invalidate logical addresses */
1005 for (i = 0; i < ctrl->num_dev; i++)
1006 ctrl->addrt[i].valid = false;
1007 mutex_unlock(&ctrl->m_ctrl);
1008 pr_info("SLIM ADSP SSR (DOWN) done");
1009}
1010
1011static void ngd_adsp_up(struct work_struct *work)
1012{
1013 struct msm_slim_qmi *qmi =
1014 container_of(work, struct msm_slim_qmi, ssr_up);
1015 struct msm_slim_ctrl *dev =
1016 container_of(qmi, struct msm_slim_ctrl, qmi);
1017 ngd_slim_enable(dev, true);
1018}
1019
Sagar Dharia71fcea52012-09-12 23:21:57 -06001020static int __devinit ngd_slim_probe(struct platform_device *pdev)
1021{
1022 struct msm_slim_ctrl *dev;
1023 int ret;
1024 struct resource *bam_mem;
1025 struct resource *slim_mem;
1026 struct resource *irq, *bam_irq;
1027 enum apr_subsys_state q6_state;
Sagar Dharia24419e32013-01-14 17:56:32 -07001028 bool rxreg_access = false;
Sagar Dharia71fcea52012-09-12 23:21:57 -06001029
1030 q6_state = apr_get_q6_state();
1031 if (q6_state == APR_SUBSYS_DOWN) {
1032 dev_dbg(&pdev->dev, "defering %s, adsp_state %d\n", __func__,
1033 q6_state);
1034 return -EPROBE_DEFER;
1035 } else
1036 dev_dbg(&pdev->dev, "adsp is ready\n");
1037
1038 slim_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
1039 "slimbus_physical");
1040 if (!slim_mem) {
1041 dev_err(&pdev->dev, "no slimbus physical memory resource\n");
1042 return -ENODEV;
1043 }
1044 bam_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
1045 "slimbus_bam_physical");
1046 if (!bam_mem) {
1047 dev_err(&pdev->dev, "no slimbus BAM memory resource\n");
1048 return -ENODEV;
1049 }
1050 irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
1051 "slimbus_irq");
1052 if (!irq) {
1053 dev_err(&pdev->dev, "no slimbus IRQ resource\n");
1054 return -ENODEV;
1055 }
1056 bam_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
1057 "slimbus_bam_irq");
1058 if (!bam_irq) {
1059 dev_err(&pdev->dev, "no slimbus BAM IRQ resource\n");
1060 return -ENODEV;
1061 }
1062
1063 dev = kzalloc(sizeof(struct msm_slim_ctrl), GFP_KERNEL);
1064 if (IS_ERR(dev)) {
1065 dev_err(&pdev->dev, "no memory for MSM slimbus controller\n");
1066 return PTR_ERR(dev);
1067 }
1068 dev->dev = &pdev->dev;
1069 platform_set_drvdata(pdev, dev);
1070 slim_set_ctrldata(&dev->ctrl, dev);
1071 dev->base = ioremap(slim_mem->start, resource_size(slim_mem));
1072 if (!dev->base) {
1073 dev_err(&pdev->dev, "IOremap failed\n");
1074 ret = -ENOMEM;
1075 goto err_ioremap_failed;
1076 }
1077 dev->bam.base = ioremap(bam_mem->start, resource_size(bam_mem));
1078 if (!dev->bam.base) {
1079 dev_err(&pdev->dev, "BAM IOremap failed\n");
1080 ret = -ENOMEM;
1081 goto err_ioremap_bam_failed;
1082 }
1083 if (pdev->dev.of_node) {
1084
1085 ret = of_property_read_u32(pdev->dev.of_node, "cell-index",
1086 &dev->ctrl.nr);
1087 if (ret) {
1088 dev_err(&pdev->dev, "Cell index not specified:%d", ret);
1089 goto err_ctrl_failed;
1090 }
Sagar Dharia24419e32013-01-14 17:56:32 -07001091 rxreg_access = of_property_read_bool(pdev->dev.of_node,
1092 "qcom,rxreg-access");
Sagar Dhariaa3c6a382013-06-21 12:18:20 -06001093 of_property_read_u32(pdev->dev.of_node, "qcom,apps-ch-pipes",
1094 &dev->pdata.apps_pipes);
1095 of_property_read_u32(pdev->dev.of_node, "qcom,ea-pc",
1096 &dev->pdata.eapc);
Sagar Dharia71fcea52012-09-12 23:21:57 -06001097 } else {
1098 dev->ctrl.nr = pdev->id;
1099 }
Sagar Dhariaa3c6a382013-06-21 12:18:20 -06001100 /*
1101 * Keep PGD's logical address as manager's. Query it when first data
1102 * channel request comes in
1103 */
1104 dev->pgdla = SLIM_LA_MGR;
Sagar Dharia71fcea52012-09-12 23:21:57 -06001105 dev->ctrl.nchans = MSM_SLIM_NCHANS;
1106 dev->ctrl.nports = MSM_SLIM_NPORTS;
1107 dev->framer.rootfreq = SLIM_ROOT_FREQ >> 3;
1108 dev->framer.superfreq =
1109 dev->framer.rootfreq / SLIM_CL_PER_SUPERFRAME_DIV8;
1110 dev->ctrl.a_framer = &dev->framer;
1111 dev->ctrl.clkgear = SLIM_MAX_CLK_GEAR;
1112 dev->ctrl.set_laddr = ngd_set_laddr;
1113 dev->ctrl.get_laddr = ngd_get_laddr;
1114 dev->ctrl.allocbw = ngd_allocbw;
1115 dev->ctrl.xfer_msg = ngd_xfer_msg;
Sagar Dhariacc1001e2012-11-06 13:56:42 -07001116 dev->ctrl.wakeup = ngd_clk_pause_wakeup;
Sagar Dharia100e7212013-05-17 18:20:57 -06001117 dev->ctrl.alloc_port = msm_alloc_port;
1118 dev->ctrl.dealloc_port = msm_dealloc_port;
Sagar Dharia71fcea52012-09-12 23:21:57 -06001119 dev->ctrl.port_xfer = msm_slim_port_xfer;
1120 dev->ctrl.port_xfer_status = msm_slim_port_xfer_status;
Sagar Dharia71fcea52012-09-12 23:21:57 -06001121 dev->bam_mem = bam_mem;
1122
1123 init_completion(&dev->reconf);
Sagar Dharia33beca02012-10-22 16:21:46 -06001124 init_completion(&dev->ctrl_up);
Sagar Dharia71fcea52012-09-12 23:21:57 -06001125 mutex_init(&dev->tx_lock);
1126 spin_lock_init(&dev->rx_lock);
1127 dev->ee = 1;
1128 dev->irq = irq->start;
1129 dev->bam.irq = bam_irq->start;
1130
Sagar Dharia24419e32013-01-14 17:56:32 -07001131 if (rxreg_access)
1132 dev->use_rx_msgqs = MSM_MSGQ_DISABLED;
1133 else
1134 dev->use_rx_msgqs = MSM_MSGQ_RESET;
Sagar Dharia5c8ad192013-05-31 11:39:05 -06001135
1136 /* Enable TX message queues by default as recommended by HW */
1137 dev->use_tx_msgqs = MSM_MSGQ_RESET;
1138
Sagar Dharia71fcea52012-09-12 23:21:57 -06001139 init_completion(&dev->rx_msgq_notify);
1140
1141 /* Register with framework */
1142 ret = slim_add_numbered_controller(&dev->ctrl);
1143 if (ret) {
1144 dev_err(dev->dev, "error adding controller\n");
1145 goto err_ctrl_failed;
1146 }
1147
1148 dev->ctrl.dev.parent = &pdev->dev;
1149 dev->ctrl.dev.of_node = pdev->dev.of_node;
Sagar Dharia33beca02012-10-22 16:21:46 -06001150 dev->state = MSM_CTRL_DOWN;
Sagar Dharia71fcea52012-09-12 23:21:57 -06001151
1152 ret = request_irq(dev->irq, ngd_slim_interrupt,
1153 IRQF_TRIGGER_HIGH, "ngd_slim_irq", dev);
1154
1155 if (ret) {
1156 dev_err(&pdev->dev, "request IRQ failed\n");
1157 goto err_request_irq_failed;
1158 }
1159
Sagar Dhariacc1001e2012-11-06 13:56:42 -07001160 init_completion(&dev->qmi.qmi_comp);
Sagar Dharia33beca02012-10-22 16:21:46 -06001161 pm_runtime_use_autosuspend(dev->dev);
1162 pm_runtime_set_autosuspend_delay(dev->dev, MSM_SLIM_AUTOSUSPEND);
1163 pm_runtime_set_suspended(dev->dev);
1164 pm_runtime_enable(dev->dev);
1165
1166 INIT_WORK(&dev->slave_notify, ngd_laddr_lookup);
1167 INIT_WORK(&dev->qmi.ssr_down, ngd_adsp_down);
1168 INIT_WORK(&dev->qmi.ssr_up, ngd_adsp_up);
Sagar Dhariacc1001e2012-11-06 13:56:42 -07001169 dev->qmi.nb.notifier_call = ngd_qmi_available;
Sagar Dharia33beca02012-10-22 16:21:46 -06001170 pm_runtime_get_noresume(dev->dev);
Sagar Dhariacc1001e2012-11-06 13:56:42 -07001171 ret = qmi_svc_event_notifier_register(SLIMBUS_QMI_SVC_ID,
1172 SLIMBUS_QMI_INS_ID, &dev->qmi.nb);
1173 if (ret) {
1174 pr_err("Slimbus QMI service registration failed:%d", ret);
1175 goto qmi_register_failed;
1176 }
1177
Sagar Dharia33beca02012-10-22 16:21:46 -06001178
Sagar Dharia71fcea52012-09-12 23:21:57 -06001179 /* Fire up the Rx message queue thread */
1180 dev->rx_msgq_thread = kthread_run(ngd_slim_rx_msgq_thread, dev,
1181 NGD_SLIM_NAME "_ngd_msgq_thread");
1182 if (IS_ERR(dev->rx_msgq_thread)) {
1183 ret = PTR_ERR(dev->rx_msgq_thread);
1184 dev_err(dev->dev, "Failed to start Rx message queue thread\n");
1185 goto err_thread_create_failed;
1186 }
1187
Sagar Dharia71fcea52012-09-12 23:21:57 -06001188 if (pdev->dev.of_node)
1189 of_register_slim_devices(&dev->ctrl);
1190
1191 /* Add devices registered with board-info now that controller is up */
1192 slim_ctrl_add_boarddevs(&dev->ctrl);
1193
Sagar Dharia71fcea52012-09-12 23:21:57 -06001194 dev_dbg(dev->dev, "NGD SB controller is up!\n");
1195 return 0;
1196
1197err_thread_create_failed:
Sagar Dhariacc1001e2012-11-06 13:56:42 -07001198 qmi_svc_event_notifier_unregister(SLIMBUS_QMI_SVC_ID,
1199 SLIMBUS_QMI_INS_ID, &dev->qmi.nb);
1200qmi_register_failed:
Sagar Dharia71fcea52012-09-12 23:21:57 -06001201 free_irq(dev->irq, dev);
1202err_request_irq_failed:
1203 slim_del_controller(&dev->ctrl);
1204err_ctrl_failed:
1205 iounmap(dev->bam.base);
1206err_ioremap_bam_failed:
1207 iounmap(dev->base);
1208err_ioremap_failed:
1209 kfree(dev);
1210 return ret;
1211}
1212
1213static int __devexit ngd_slim_remove(struct platform_device *pdev)
1214{
1215 struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
Sagar Dhariacc1001e2012-11-06 13:56:42 -07001216 ngd_slim_enable(dev, false);
1217 qmi_svc_event_notifier_unregister(SLIMBUS_QMI_SVC_ID,
1218 SLIMBUS_QMI_INS_ID, &dev->qmi.nb);
Sagar Dharia71fcea52012-09-12 23:21:57 -06001219 pm_runtime_disable(&pdev->dev);
Sagar Dharia71fcea52012-09-12 23:21:57 -06001220 free_irq(dev->irq, dev);
1221 slim_del_controller(&dev->ctrl);
1222 kthread_stop(dev->rx_msgq_thread);
1223 iounmap(dev->bam.base);
1224 iounmap(dev->base);
1225 kfree(dev);
1226 return 0;
1227}
1228
1229#ifdef CONFIG_PM_RUNTIME
1230static int ngd_slim_runtime_idle(struct device *device)
1231{
1232 dev_dbg(device, "pm_runtime: idle...\n");
1233 pm_request_autosuspend(device);
1234 return -EAGAIN;
1235}
1236#endif
1237
1238/*
1239 * If PM_RUNTIME is not defined, these 2 functions become helper
1240 * functions to be called from system suspend/resume. So they are not
1241 * inside ifdef CONFIG_PM_RUNTIME
1242 */
Sagar Dharia71fcea52012-09-12 23:21:57 -06001243static int ngd_slim_runtime_resume(struct device *device)
1244{
1245 struct platform_device *pdev = to_platform_device(device);
1246 struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
1247 int ret = 0;
Sagar Dharia33beca02012-10-22 16:21:46 -06001248 if (dev->state >= MSM_CTRL_ASLEEP)
Sagar Dharia71fcea52012-09-12 23:21:57 -06001249 ret = slim_ctrl_clk_pause(&dev->ctrl, true, 0);
1250 if (ret) {
1251 dev_err(device, "clk pause not exited:%d", ret);
1252 dev->state = MSM_CTRL_ASLEEP;
1253 } else {
1254 dev->state = MSM_CTRL_AWAKE;
1255 }
1256 return ret;
1257}
1258
Sagar Dharia33beca02012-10-22 16:21:46 -06001259#ifdef CONFIG_PM_SLEEP
1260static int ngd_slim_runtime_suspend(struct device *device)
1261{
1262 struct platform_device *pdev = to_platform_device(device);
1263 struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
1264 int ret = 0;
1265 dev->state = MSM_CTRL_SLEEPING;
1266 ret = slim_ctrl_clk_pause(&dev->ctrl, false, SLIM_CLK_UNSPECIFIED);
1267 if (ret) {
1268 if (ret != -EBUSY)
1269 dev_err(device, "clk pause not entered:%d", ret);
1270 dev->state = MSM_CTRL_AWAKE;
1271 } else {
1272 dev->state = MSM_CTRL_ASLEEP;
1273 }
1274 return ret;
1275}
1276
Sagar Dharia71fcea52012-09-12 23:21:57 -06001277static int ngd_slim_suspend(struct device *dev)
1278{
1279 int ret = -EBUSY;
1280 if (!pm_runtime_enabled(dev) || !pm_runtime_suspended(dev)) {
1281 dev_dbg(dev, "system suspend");
1282 ret = ngd_slim_runtime_suspend(dev);
Sagar Dhariaa1398282013-01-22 13:26:20 -07001283 /*
1284 * If runtime-PM still thinks it's active, then make sure its
1285 * status is in sync with HW status.
1286 * Since this suspend calls QMI api, it results in holding a
1287 * wakelock. That results in failure of first suspend.
1288 * Subsequent suspend should not call low-power transition
1289 * again since the HW is already in suspended state.
1290 */
1291 if (!ret) {
1292 pm_runtime_disable(dev);
1293 pm_runtime_set_suspended(dev);
1294 pm_runtime_enable(dev);
1295 }
Sagar Dharia71fcea52012-09-12 23:21:57 -06001296 }
1297 if (ret == -EBUSY) {
1298 /*
1299 * There is a possibility that some audio stream is active
1300 * during suspend. We dont want to return suspend failure in
1301 * that case so that display and relevant components can still
1302 * go to suspend.
1303 * If there is some other error, then it should be passed-on
1304 * to system level suspend
1305 */
1306 ret = 0;
1307 }
1308 return ret;
1309}
1310
1311static int ngd_slim_resume(struct device *dev)
1312{
Sagar Dhariaa1398282013-01-22 13:26:20 -07001313 /*
1314 * Rely on runtime-PM to call resume in case it is enabled.
1315 * Even if it's not enabled, rely on 1st client transaction to do
1316 * clock/power on
1317 */
Sagar Dharia71fcea52012-09-12 23:21:57 -06001318 return 0;
1319}
1320#endif /* CONFIG_PM_SLEEP */
1321
1322static const struct dev_pm_ops ngd_slim_dev_pm_ops = {
1323 SET_SYSTEM_SLEEP_PM_OPS(
1324 ngd_slim_suspend,
1325 ngd_slim_resume
1326 )
1327 SET_RUNTIME_PM_OPS(
1328 ngd_slim_runtime_suspend,
1329 ngd_slim_runtime_resume,
1330 ngd_slim_runtime_idle
1331 )
1332};
1333
1334static struct of_device_id ngd_slim_dt_match[] = {
1335 {
1336 .compatible = "qcom,slim-ngd",
1337 },
1338 {}
1339};
1340
1341static struct platform_driver ngd_slim_driver = {
1342 .probe = ngd_slim_probe,
1343 .remove = ngd_slim_remove,
1344 .driver = {
1345 .name = NGD_SLIM_NAME,
1346 .owner = THIS_MODULE,
1347 .pm = &ngd_slim_dev_pm_ops,
1348 .of_match_table = ngd_slim_dt_match,
1349 },
1350};
1351
1352static int ngd_slim_init(void)
1353{
1354 return platform_driver_register(&ngd_slim_driver);
1355}
1356late_initcall(ngd_slim_init);
1357
1358static void ngd_slim_exit(void)
1359{
1360 platform_driver_unregister(&ngd_slim_driver);
1361}
1362module_exit(ngd_slim_exit);
1363
1364MODULE_LICENSE("GPL v2");
1365MODULE_DESCRIPTION("MSM Slimbus controller");
1366MODULE_ALIAS("platform:msm-slim-ngd");