aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJayachandran B <jayachandran.b@intel.com>2016-11-03 07:37:17 -0400
committerMark Brown <broonie@kernel.org>2016-11-03 13:14:22 -0400
commit5bb4cd46ace5f220fbc34370e7fe9ba515ead9f8 (patch)
tree4a604053780d18f5450c7d022559cafe9ff62c6a
parenta26a3f53e3d2bfeb666ca31b5f86c65a1816eb89 (diff)
ASoC: Intel: Skylake: Add D0iX callbacks
The driver needs two DSP callback, one to set D0i0 (active) and D0i3 (low-power) states. Add these callbacks in dsp ops and implement them for broxton platforms. Signed-off-by: Jayachandran B <jayachandran.b@intel.com> Signed-off-by: Vinod Koul <vinod.koul@intel.com> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--sound/soc/intel/skylake/bxt-sst.c140
-rw-r--r--sound/soc/intel/skylake/skl-sst-dsp.h12
-rw-r--r--sound/soc/intel/skylake/skl-sst-ipc.h19
3 files changed, 171 insertions, 0 deletions
diff --git a/sound/soc/intel/skylake/bxt-sst.c b/sound/soc/intel/skylake/bxt-sst.c
index 1d251d59bcb9..fed818fe2e69 100644
--- a/sound/soc/intel/skylake/bxt-sst.c
+++ b/sound/soc/intel/skylake/bxt-sst.c
@@ -43,6 +43,9 @@
43 43
44#define BXT_ADSP_FW_BIN_HDR_OFFSET 0x2000 44#define BXT_ADSP_FW_BIN_HDR_OFFSET 0x2000
45 45
46/* Delay before scheduling D0i3 entry */
47#define BXT_D0I3_DELAY 5000
48
46static unsigned int bxt_get_errorcode(struct sst_dsp *ctx) 49static unsigned int bxt_get_errorcode(struct sst_dsp *ctx)
47{ 50{
48 return sst_dsp_shim_read(ctx, BXT_ADSP_ERROR_CODE); 51 return sst_dsp_shim_read(ctx, BXT_ADSP_ERROR_CODE);
@@ -288,6 +291,141 @@ sst_load_base_firmware_failed:
288 return ret; 291 return ret;
289} 292}
290 293
294/*
295 * Decide the D0i3 state that can be targeted based on the usecase
296 * ref counts and DSP state
297 *
298 * Decision Matrix: (X= dont care; state = target state)
299 *
300 * DSP state != SKL_DSP_RUNNING ; state = no d0i3
301 *
302 * DSP state == SKL_DSP_RUNNING , the following matrix applies
303 * non_d0i3 >0; streaming =X; non_streaming =X; state = no d0i3
304 * non_d0i3 =X; streaming =0; non_streaming =0; state = no d0i3
305 * non_d0i3 =0; streaming >0; non_streaming =X; state = streaming d0i3
306 * non_d0i3 =0; streaming =0; non_streaming =X; state = non-streaming d0i3
307 */
308static int bxt_d0i3_target_state(struct sst_dsp *ctx)
309{
310 struct skl_sst *skl = ctx->thread_context;
311 struct skl_d0i3_data *d0i3 = &skl->d0i3;
312
313 if (skl->cores.state[SKL_DSP_CORE0_ID] != SKL_DSP_RUNNING)
314 return SKL_DSP_D0I3_NONE;
315
316 if (d0i3->non_d0i3)
317 return SKL_DSP_D0I3_NONE;
318 else if (d0i3->streaming)
319 return SKL_DSP_D0I3_STREAMING;
320 else if (d0i3->non_streaming)
321 return SKL_DSP_D0I3_NON_STREAMING;
322 else
323 return SKL_DSP_D0I3_NONE;
324}
325
326static void bxt_set_dsp_D0i3(struct work_struct *work)
327{
328 int ret;
329 struct skl_ipc_d0ix_msg msg;
330 struct skl_sst *skl = container_of(work,
331 struct skl_sst, d0i3.work.work);
332 struct sst_dsp *ctx = skl->dsp;
333 struct skl_d0i3_data *d0i3 = &skl->d0i3;
334 int target_state;
335
336 dev_dbg(ctx->dev, "In %s:\n", __func__);
337
338 /* D0i3 entry allowed only if core 0 alone is running */
339 if (skl_dsp_get_enabled_cores(ctx) != SKL_DSP_CORE0_MASK) {
340 dev_warn(ctx->dev,
341 "D0i3 allowed when only core0 running:Exit\n");
342 return;
343 }
344
345 target_state = bxt_d0i3_target_state(ctx);
346 if (target_state == SKL_DSP_D0I3_NONE)
347 return;
348
349 msg.instance_id = 0;
350 msg.module_id = 0;
351 msg.wake = 1;
352 msg.streaming = 0;
353 if (target_state == SKL_DSP_D0I3_STREAMING)
354 msg.streaming = 1;
355
356 ret = skl_ipc_set_d0ix(&skl->ipc, &msg);
357
358 if (ret < 0) {
359 dev_err(ctx->dev, "Failed to set DSP to D0i3 state\n");
360 return;
361 }
362
363 /* Set Vendor specific register D0I3C.I3 to enable D0i3*/
364 if (skl->update_d0i3c)
365 skl->update_d0i3c(skl->dev, true);
366
367 d0i3->state = target_state;
368 skl->cores.state[SKL_DSP_CORE0_ID] = SKL_DSP_RUNNING_D0I3;
369}
370
371static int bxt_schedule_dsp_D0i3(struct sst_dsp *ctx)
372{
373 struct skl_sst *skl = ctx->thread_context;
374 struct skl_d0i3_data *d0i3 = &skl->d0i3;
375
376 /* Schedule D0i3 only if the usecase ref counts are appropriate */
377 if (bxt_d0i3_target_state(ctx) != SKL_DSP_D0I3_NONE) {
378
379 dev_dbg(ctx->dev, "%s: Schedule D0i3\n", __func__);
380
381 schedule_delayed_work(&d0i3->work,
382 msecs_to_jiffies(BXT_D0I3_DELAY));
383 }
384
385 return 0;
386}
387
388static int bxt_set_dsp_D0i0(struct sst_dsp *ctx)
389{
390 int ret;
391 struct skl_ipc_d0ix_msg msg;
392 struct skl_sst *skl = ctx->thread_context;
393
394 dev_dbg(ctx->dev, "In %s:\n", __func__);
395
396 /* First Cancel any pending attempt to put DSP to D0i3 */
397 cancel_delayed_work_sync(&skl->d0i3.work);
398
399 /* If DSP is currently in D0i3, bring it to D0i0 */
400 if (skl->cores.state[SKL_DSP_CORE0_ID] != SKL_DSP_RUNNING_D0I3)
401 return 0;
402
403 dev_dbg(ctx->dev, "Set DSP to D0i0\n");
404
405 msg.instance_id = 0;
406 msg.module_id = 0;
407 msg.streaming = 0;
408 msg.wake = 0;
409
410 if (skl->d0i3.state == SKL_DSP_D0I3_STREAMING)
411 msg.streaming = 1;
412
413 /* Clear Vendor specific register D0I3C.I3 to disable D0i3*/
414 if (skl->update_d0i3c)
415 skl->update_d0i3c(skl->dev, false);
416
417 ret = skl_ipc_set_d0ix(&skl->ipc, &msg);
418 if (ret < 0) {
419 dev_err(ctx->dev, "Failed to set DSP to D0i0\n");
420 return ret;
421 }
422
423 skl->cores.state[SKL_DSP_CORE0_ID] = SKL_DSP_RUNNING;
424 skl->d0i3.state = SKL_DSP_D0I3_NONE;
425
426 return 0;
427}
428
291static int bxt_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id) 429static int bxt_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id)
292{ 430{
293 struct skl_sst *skl = ctx->thread_context; 431 struct skl_sst *skl = ctx->thread_context;
@@ -414,6 +552,8 @@ static int bxt_set_dsp_D3(struct sst_dsp *ctx, unsigned int core_id)
414static struct skl_dsp_fw_ops bxt_fw_ops = { 552static struct skl_dsp_fw_ops bxt_fw_ops = {
415 .set_state_D0 = bxt_set_dsp_D0, 553 .set_state_D0 = bxt_set_dsp_D0,
416 .set_state_D3 = bxt_set_dsp_D3, 554 .set_state_D3 = bxt_set_dsp_D3,
555 .set_state_D0i3 = bxt_schedule_dsp_D0i3,
556 .set_state_D0i0 = bxt_set_dsp_D0i0,
417 .load_fw = bxt_load_base_firmware, 557 .load_fw = bxt_load_base_firmware,
418 .get_fw_errcode = bxt_get_errorcode, 558 .get_fw_errcode = bxt_get_errorcode,
419 .load_library = bxt_load_library, 559 .load_library = bxt_load_library,
diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h
index b9e71d051fb1..7c272ba0f4b5 100644
--- a/sound/soc/intel/skylake/skl-sst-dsp.h
+++ b/sound/soc/intel/skylake/skl-sst-dsp.h
@@ -126,11 +126,21 @@ struct sst_dsp_device;
126#define SKL_ADSPCS_CPA_SHIFT 24 126#define SKL_ADSPCS_CPA_SHIFT 24
127#define SKL_ADSPCS_CPA_MASK(cm) ((cm) << SKL_ADSPCS_CPA_SHIFT) 127#define SKL_ADSPCS_CPA_MASK(cm) ((cm) << SKL_ADSPCS_CPA_SHIFT)
128 128
129/* DSP Core state */
129enum skl_dsp_states { 130enum skl_dsp_states {
130 SKL_DSP_RUNNING = 1, 131 SKL_DSP_RUNNING = 1,
132 /* Running in D0i3 state; can be in streaming or non-streaming D0i3 */
133 SKL_DSP_RUNNING_D0I3, /* Running in D0i3 state*/
131 SKL_DSP_RESET, 134 SKL_DSP_RESET,
132}; 135};
133 136
137/* D0i3 substates */
138enum skl_dsp_d0i3_states {
139 SKL_DSP_D0I3_NONE = -1, /* No D0i3 */
140 SKL_DSP_D0I3_NON_STREAMING = 0,
141 SKL_DSP_D0I3_STREAMING = 1,
142};
143
134struct skl_dsp_fw_ops { 144struct skl_dsp_fw_ops {
135 int (*load_fw)(struct sst_dsp *ctx); 145 int (*load_fw)(struct sst_dsp *ctx);
136 /* FW module parser/loader */ 146 /* FW module parser/loader */
@@ -139,6 +149,8 @@ struct skl_dsp_fw_ops {
139 int (*parse_fw)(struct sst_dsp *ctx); 149 int (*parse_fw)(struct sst_dsp *ctx);
140 int (*set_state_D0)(struct sst_dsp *ctx, unsigned int core_id); 150 int (*set_state_D0)(struct sst_dsp *ctx, unsigned int core_id);
141 int (*set_state_D3)(struct sst_dsp *ctx, unsigned int core_id); 151 int (*set_state_D3)(struct sst_dsp *ctx, unsigned int core_id);
152 int (*set_state_D0i3)(struct sst_dsp *ctx);
153 int (*set_state_D0i0)(struct sst_dsp *ctx);
142 unsigned int (*get_fw_errcode)(struct sst_dsp *ctx); 154 unsigned int (*get_fw_errcode)(struct sst_dsp *ctx);
143 int (*load_mod)(struct sst_dsp *ctx, u16 mod_id, u8 *mod_name); 155 int (*load_mod)(struct sst_dsp *ctx, u16 mod_id, u8 *mod_name);
144 int (*unload_mod)(struct sst_dsp *ctx, u16 mod_id); 156 int (*unload_mod)(struct sst_dsp *ctx, u16 mod_id);
diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h
index ef2182d21934..a45c42046b64 100644
--- a/sound/soc/intel/skylake/skl-sst-ipc.h
+++ b/sound/soc/intel/skylake/skl-sst-ipc.h
@@ -53,6 +53,23 @@ struct skl_dsp_cores {
53 int usage_count[SKL_DSP_CORES_MAX]; 53 int usage_count[SKL_DSP_CORES_MAX];
54}; 54};
55 55
56/**
57 * skl_d0i3_data: skl D0i3 counters data struct
58 *
59 * @streaming: Count of usecases that can attempt streaming D0i3
60 * @non_streaming: Count of usecases that can attempt non-streaming D0i3
61 * @non_d0i3: Count of usecases that cannot attempt D0i3
62 * @state: current state
63 * @work: D0i3 worker thread
64 */
65struct skl_d0i3_data {
66 int streaming;
67 int non_streaming;
68 int non_d0i3;
69 enum skl_dsp_d0i3_states state;
70 struct delayed_work work;
71};
72
56struct skl_sst { 73struct skl_sst {
57 struct device *dev; 74 struct device *dev;
58 struct sst_dsp *dsp; 75 struct sst_dsp *dsp;
@@ -86,6 +103,8 @@ struct skl_sst {
86 103
87 /* Callback to update D0i3C register */ 104 /* Callback to update D0i3C register */
88 void (*update_d0i3c)(struct device *dev, bool enable); 105 void (*update_d0i3c)(struct device *dev, bool enable);
106
107 struct skl_d0i3_data d0i3;
89}; 108};
90 109
91struct skl_ipc_init_instance_msg { 110struct skl_ipc_init_instance_msg {