linux/sound/soc/sof/intel/cnl.c
<<
>>
Prefs
   1// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
   2//
   3// This file is provided under a dual BSD/GPLv2 license.  When using or
   4// redistributing this file, you may do so under either license.
   5//
   6// Copyright(c) 2018 Intel Corporation. All rights reserved.
   7//
   8// Authors: Liam Girdwood <liam.r.girdwood@linux.intel.com>
   9//          Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
  10//          Rander Wang <rander.wang@intel.com>
  11//          Keyon Jie <yang.jie@linux.intel.com>
  12//
  13
  14/*
  15 * Hardware interface for audio DSP on Cannonlake.
  16 */
  17
  18#include "../ops.h"
  19#include "hda.h"
  20
  21static const struct snd_sof_debugfs_map cnl_dsp_debugfs[] = {
  22        {"hda", HDA_DSP_HDA_BAR, 0, 0x4000, SOF_DEBUGFS_ACCESS_ALWAYS},
  23        {"pp", HDA_DSP_PP_BAR,  0, 0x1000, SOF_DEBUGFS_ACCESS_ALWAYS},
  24        {"dsp", HDA_DSP_BAR,  0, 0x10000, SOF_DEBUGFS_ACCESS_ALWAYS},
  25};
  26
  27static void cnl_ipc_host_done(struct snd_sof_dev *sdev);
  28static void cnl_ipc_dsp_done(struct snd_sof_dev *sdev);
  29
  30static irqreturn_t cnl_ipc_irq_thread(int irq, void *context)
  31{
  32        struct snd_sof_dev *sdev = context;
  33        u32 hipci;
  34        u32 hipcctl;
  35        u32 hipcida;
  36        u32 hipctdr;
  37        u32 hipctdd;
  38        u32 msg;
  39        u32 msg_ext;
  40        irqreturn_t ret = IRQ_NONE;
  41
  42        hipcida = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDA);
  43        hipcctl = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCCTL);
  44        hipctdr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCTDR);
  45
  46        /* reenable IPC interrupt */
  47        snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC,
  48                                HDA_DSP_ADSPIC_IPC, HDA_DSP_ADSPIC_IPC);
  49
  50        /* reply message from DSP */
  51        if (hipcida & CNL_DSP_REG_HIPCIDA_DONE &&
  52            hipcctl & CNL_DSP_REG_HIPCCTL_DONE) {
  53                hipci = snd_sof_dsp_read(sdev, HDA_DSP_BAR,
  54                                         CNL_DSP_REG_HIPCIDR);
  55                msg_ext = hipci & CNL_DSP_REG_HIPCIDR_MSG_MASK;
  56                msg = hipcida & CNL_DSP_REG_HIPCIDA_MSG_MASK;
  57
  58                dev_vdbg(sdev->dev,
  59                         "ipc: firmware response, msg:0x%x, msg_ext:0x%x\n",
  60                         msg, msg_ext);
  61
  62                /* mask Done interrupt */
  63                snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR,
  64                                        CNL_DSP_REG_HIPCCTL,
  65                                        CNL_DSP_REG_HIPCCTL_DONE, 0);
  66
  67                spin_lock_irq(&sdev->ipc_lock);
  68
  69                /* handle immediate reply from DSP core */
  70                hda_dsp_ipc_get_reply(sdev);
  71                snd_sof_ipc_reply(sdev, msg);
  72
  73                if (sdev->code_loading) {
  74                        sdev->code_loading = 0;
  75                        wake_up(&sdev->waitq);
  76                }
  77
  78                cnl_ipc_dsp_done(sdev);
  79
  80                spin_unlock_irq(&sdev->ipc_lock);
  81
  82                ret = IRQ_HANDLED;
  83        }
  84
  85        /* new message from DSP */
  86        if (hipctdr & CNL_DSP_REG_HIPCTDR_BUSY) {
  87                hipctdd = snd_sof_dsp_read(sdev, HDA_DSP_BAR,
  88                                           CNL_DSP_REG_HIPCTDD);
  89                msg = hipctdr & CNL_DSP_REG_HIPCTDR_MSG_MASK;
  90                msg_ext = hipctdd & CNL_DSP_REG_HIPCTDD_MSG_MASK;
  91
  92                dev_vdbg(sdev->dev,
  93                         "ipc: firmware initiated, msg:0x%x, msg_ext:0x%x\n",
  94                         msg, msg_ext);
  95
  96                /* handle messages from DSP */
  97                if ((hipctdr & SOF_IPC_PANIC_MAGIC_MASK) ==
  98                   SOF_IPC_PANIC_MAGIC) {
  99                        snd_sof_dsp_panic(sdev, HDA_DSP_PANIC_OFFSET(msg_ext));
 100                } else {
 101                        snd_sof_ipc_msgs_rx(sdev);
 102                }
 103
 104                /*
 105                 * clear busy interrupt to tell dsp controller this
 106                 * interrupt has been accepted, not trigger it again
 107                 */
 108                snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR,
 109                                               CNL_DSP_REG_HIPCTDR,
 110                                               CNL_DSP_REG_HIPCTDR_BUSY,
 111                                               CNL_DSP_REG_HIPCTDR_BUSY);
 112
 113                cnl_ipc_host_done(sdev);
 114
 115                ret = IRQ_HANDLED;
 116        }
 117
 118        return ret;
 119}
 120
 121static void cnl_ipc_host_done(struct snd_sof_dev *sdev)
 122{
 123        /*
 124         * set done bit to ack dsp the msg has been
 125         * processed and send reply msg to dsp
 126         */
 127        snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR,
 128                                       CNL_DSP_REG_HIPCTDA,
 129                                       CNL_DSP_REG_HIPCTDA_DONE,
 130                                       CNL_DSP_REG_HIPCTDA_DONE);
 131}
 132
 133static void cnl_ipc_dsp_done(struct snd_sof_dev *sdev)
 134{
 135        /*
 136         * set DONE bit - tell DSP we have received the reply msg
 137         * from DSP, and processed it, don't send more reply to host
 138         */
 139        snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR,
 140                                       CNL_DSP_REG_HIPCIDA,
 141                                       CNL_DSP_REG_HIPCIDA_DONE,
 142                                       CNL_DSP_REG_HIPCIDA_DONE);
 143
 144        /* unmask Done interrupt */
 145        snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR,
 146                                CNL_DSP_REG_HIPCCTL,
 147                                CNL_DSP_REG_HIPCCTL_DONE,
 148                                CNL_DSP_REG_HIPCCTL_DONE);
 149}
 150
 151static int cnl_ipc_send_msg(struct snd_sof_dev *sdev,
 152                            struct snd_sof_ipc_msg *msg)
 153{
 154        u32 cmd = msg->header;
 155
 156        /* send the message */
 157        sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data,
 158                          msg->msg_size);
 159        snd_sof_dsp_write(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDR,
 160                          cmd | CNL_DSP_REG_HIPCIDR_BUSY);
 161
 162        return 0;
 163}
 164
 165static void cnl_ipc_dump(struct snd_sof_dev *sdev)
 166{
 167        u32 hipcctl;
 168        u32 hipcida;
 169        u32 hipctdr;
 170
 171        /* read IPC status */
 172        hipcida = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDA);
 173        hipcctl = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCCTL);
 174        hipctdr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCTDR);
 175
 176        /* dump the IPC regs */
 177        /* TODO: parse the raw msg */
 178        dev_err(sdev->dev,
 179                "error: host status 0x%8.8x dsp status 0x%8.8x mask 0x%8.8x\n",
 180                hipcida, hipctdr, hipcctl);
 181}
 182
 183/* cannonlake ops */
 184const struct snd_sof_dsp_ops sof_cnl_ops = {
 185        /* probe and remove */
 186        .probe          = hda_dsp_probe,
 187        .remove         = hda_dsp_remove,
 188
 189        /* Register IO */
 190        .write          = sof_io_write,
 191        .read           = sof_io_read,
 192        .write64        = sof_io_write64,
 193        .read64         = sof_io_read64,
 194
 195        /* Block IO */
 196        .block_read     = sof_block_read,
 197        .block_write    = sof_block_write,
 198
 199        /* doorbell */
 200        .irq_handler    = hda_dsp_ipc_irq_handler,
 201        .irq_thread     = cnl_ipc_irq_thread,
 202
 203        /* ipc */
 204        .send_msg       = cnl_ipc_send_msg,
 205        .fw_ready       = hda_dsp_ipc_fw_ready,
 206
 207        .ipc_msg_data   = hda_ipc_msg_data,
 208        .ipc_pcm_params = hda_ipc_pcm_params,
 209
 210        /* debug */
 211        .debug_map      = cnl_dsp_debugfs,
 212        .debug_map_count        = ARRAY_SIZE(cnl_dsp_debugfs),
 213        .dbg_dump       = hda_dsp_dump,
 214        .ipc_dump       = cnl_ipc_dump,
 215
 216        /* stream callbacks */
 217        .pcm_open       = hda_dsp_pcm_open,
 218        .pcm_close      = hda_dsp_pcm_close,
 219        .pcm_hw_params  = hda_dsp_pcm_hw_params,
 220        .pcm_trigger    = hda_dsp_pcm_trigger,
 221        .pcm_pointer    = hda_dsp_pcm_pointer,
 222
 223        /* firmware loading */
 224        .load_firmware = snd_sof_load_firmware_raw,
 225
 226        /* pre/post fw run */
 227        .pre_fw_run = hda_dsp_pre_fw_run,
 228        .post_fw_run = hda_dsp_post_fw_run,
 229
 230        /* dsp core power up/down */
 231        .core_power_up = hda_dsp_enable_core,
 232        .core_power_down = hda_dsp_core_reset_power_down,
 233
 234        /* firmware run */
 235        .run = hda_dsp_cl_boot_firmware,
 236
 237        /* trace callback */
 238        .trace_init = hda_dsp_trace_init,
 239        .trace_release = hda_dsp_trace_release,
 240        .trace_trigger = hda_dsp_trace_trigger,
 241
 242        /* DAI drivers */
 243        .drv            = skl_dai,
 244        .num_drv        = SOF_SKL_NUM_DAIS,
 245
 246        /* PM */
 247        .suspend                = hda_dsp_suspend,
 248        .resume                 = hda_dsp_resume,
 249        .runtime_suspend        = hda_dsp_runtime_suspend,
 250        .runtime_resume         = hda_dsp_runtime_resume,
 251        .set_hw_params_upon_resume = hda_dsp_set_hw_params_upon_resume,
 252};
 253EXPORT_SYMBOL(sof_cnl_ops);
 254
 255const struct sof_intel_dsp_desc cnl_chip_info = {
 256        /* Cannonlake */
 257        .cores_num = 4,
 258        .init_core_mask = 1,
 259        .cores_mask = HDA_DSP_CORE_MASK(0) |
 260                                HDA_DSP_CORE_MASK(1) |
 261                                HDA_DSP_CORE_MASK(2) |
 262                                HDA_DSP_CORE_MASK(3),
 263        .ipc_req = CNL_DSP_REG_HIPCIDR,
 264        .ipc_req_mask = CNL_DSP_REG_HIPCIDR_BUSY,
 265        .ipc_ack = CNL_DSP_REG_HIPCIDA,
 266        .ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE,
 267        .ipc_ctl = CNL_DSP_REG_HIPCCTL,
 268        .rom_init_timeout       = 300,
 269        .ssp_count = CNL_SSP_COUNT,
 270        .ssp_base_offset = CNL_SSP_BASE_OFFSET,
 271};
 272EXPORT_SYMBOL(cnl_chip_info);
 273