2019-04-12 11:08:58 -05:00
// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
//
// This file is provided under a dual BSD/GPLv2 license. When using or
// redistributing this file, you may do so under either license.
//
// Copyright(c) 2018 Intel Corporation. All rights reserved.
//
// Authors: Liam Girdwood <liam.r.girdwood@linux.intel.com>
// Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
// Rander Wang <rander.wang@intel.com>
// Keyon Jie <yang.jie@linux.intel.com>
//
/*
* Hardware interface for audio DSP on Cannonlake .
*/
# include "../ops.h"
# include "hda.h"
static const struct snd_sof_debugfs_map cnl_dsp_debugfs [ ] = {
{ " hda " , HDA_DSP_HDA_BAR , 0 , 0x4000 , SOF_DEBUGFS_ACCESS_ALWAYS } ,
{ " pp " , HDA_DSP_PP_BAR , 0 , 0x1000 , SOF_DEBUGFS_ACCESS_ALWAYS } ,
{ " dsp " , HDA_DSP_BAR , 0 , 0x10000 , SOF_DEBUGFS_ACCESS_ALWAYS } ,
} ;
static void cnl_ipc_host_done ( struct snd_sof_dev * sdev ) ;
static void cnl_ipc_dsp_done ( struct snd_sof_dev * sdev ) ;
static irqreturn_t cnl_ipc_irq_thread ( int irq , void * context )
{
struct snd_sof_dev * sdev = context ;
u32 hipci ;
u32 hipcctl ;
u32 hipcida ;
u32 hipctdr ;
u32 hipctdd ;
u32 msg ;
u32 msg_ext ;
2019-06-03 11:20:28 -05:00
bool ipc_irq = false ;
2019-04-12 11:08:58 -05:00
hipcida = snd_sof_dsp_read ( sdev , HDA_DSP_BAR , CNL_DSP_REG_HIPCIDA ) ;
hipcctl = snd_sof_dsp_read ( sdev , HDA_DSP_BAR , CNL_DSP_REG_HIPCCTL ) ;
hipctdr = snd_sof_dsp_read ( sdev , HDA_DSP_BAR , CNL_DSP_REG_HIPCTDR ) ;
2019-06-03 11:20:26 -05:00
hipctdd = snd_sof_dsp_read ( sdev , HDA_DSP_BAR , CNL_DSP_REG_HIPCTDD ) ;
hipci = snd_sof_dsp_read ( sdev , HDA_DSP_BAR , CNL_DSP_REG_HIPCIDR ) ;
2019-04-12 11:08:58 -05:00
/* reply message from DSP */
if ( hipcida & CNL_DSP_REG_HIPCIDA_DONE & &
hipcctl & CNL_DSP_REG_HIPCCTL_DONE ) {
msg_ext = hipci & CNL_DSP_REG_HIPCIDR_MSG_MASK ;
msg = hipcida & CNL_DSP_REG_HIPCIDA_MSG_MASK ;
dev_vdbg ( sdev - > dev ,
" ipc: firmware response, msg:0x%x, msg_ext:0x%x \n " ,
msg , msg_ext ) ;
/* mask Done interrupt */
snd_sof_dsp_update_bits ( sdev , HDA_DSP_BAR ,
CNL_DSP_REG_HIPCCTL ,
CNL_DSP_REG_HIPCCTL_DONE , 0 ) ;
2019-05-24 14:09:23 -05:00
spin_lock_irq ( & sdev - > ipc_lock ) ;
2019-04-12 11:08:58 -05:00
/* handle immediate reply from DSP core */
hda_dsp_ipc_get_reply ( sdev ) ;
snd_sof_ipc_reply ( sdev , msg ) ;
if ( sdev - > code_loading ) {
sdev - > code_loading = 0 ;
wake_up ( & sdev - > waitq ) ;
}
cnl_ipc_dsp_done ( sdev ) ;
2019-05-24 14:09:23 -05:00
spin_unlock_irq ( & sdev - > ipc_lock ) ;
2019-06-03 11:20:28 -05:00
ipc_irq = true ;
2019-04-12 11:08:58 -05:00
}
/* new message from DSP */
if ( hipctdr & CNL_DSP_REG_HIPCTDR_BUSY ) {
msg = hipctdr & CNL_DSP_REG_HIPCTDR_MSG_MASK ;
msg_ext = hipctdd & CNL_DSP_REG_HIPCTDD_MSG_MASK ;
dev_vdbg ( sdev - > dev ,
" ipc: firmware initiated, msg:0x%x, msg_ext:0x%x \n " ,
msg , msg_ext ) ;
/* handle messages from DSP */
if ( ( hipctdr & SOF_IPC_PANIC_MAGIC_MASK ) = =
SOF_IPC_PANIC_MAGIC ) {
snd_sof_dsp_panic ( sdev , HDA_DSP_PANIC_OFFSET ( msg_ext ) ) ;
} else {
snd_sof_ipc_msgs_rx ( sdev ) ;
}
cnl_ipc_host_done ( sdev ) ;
2019-06-03 11:20:28 -05:00
ipc_irq = true ;
}
if ( ! ipc_irq ) {
/*
* This interrupt is not shared so no need to return IRQ_NONE .
*/
dev_err_ratelimited ( sdev - > dev ,
" error: nothing to do in IRQ thread \n " ) ;
2019-04-12 11:08:58 -05:00
}
2019-06-03 11:20:28 -05:00
/* re-enable IPC interrupt */
snd_sof_dsp_update_bits ( sdev , HDA_DSP_BAR , HDA_DSP_REG_ADSPIC ,
HDA_DSP_ADSPIC_IPC , HDA_DSP_ADSPIC_IPC ) ;
return IRQ_HANDLED ;
2019-04-12 11:08:58 -05:00
}
static void cnl_ipc_host_done ( struct snd_sof_dev * sdev )
{
2019-06-03 11:20:27 -05:00
/*
* clear busy interrupt to tell dsp controller this
* interrupt has been accepted , not trigger it again
*/
snd_sof_dsp_update_bits_forced ( sdev , HDA_DSP_BAR ,
CNL_DSP_REG_HIPCTDR ,
CNL_DSP_REG_HIPCTDR_BUSY ,
CNL_DSP_REG_HIPCTDR_BUSY ) ;
2019-04-12 11:08:58 -05:00
/*
* set done bit to ack dsp the msg has been
* processed and send reply msg to dsp
*/
snd_sof_dsp_update_bits_forced ( sdev , HDA_DSP_BAR ,
CNL_DSP_REG_HIPCTDA ,
CNL_DSP_REG_HIPCTDA_DONE ,
CNL_DSP_REG_HIPCTDA_DONE ) ;
}
static void cnl_ipc_dsp_done ( struct snd_sof_dev * sdev )
{
/*
* set DONE bit - tell DSP we have received the reply msg
* from DSP , and processed it , don ' t send more reply to host
*/
snd_sof_dsp_update_bits_forced ( sdev , HDA_DSP_BAR ,
CNL_DSP_REG_HIPCIDA ,
CNL_DSP_REG_HIPCIDA_DONE ,
CNL_DSP_REG_HIPCIDA_DONE ) ;
/* unmask Done interrupt */
snd_sof_dsp_update_bits ( sdev , HDA_DSP_BAR ,
CNL_DSP_REG_HIPCCTL ,
CNL_DSP_REG_HIPCCTL_DONE ,
CNL_DSP_REG_HIPCCTL_DONE ) ;
}
static int cnl_ipc_send_msg ( struct snd_sof_dev * sdev ,
struct snd_sof_ipc_msg * msg )
{
/* send the message */
sof_mailbox_write ( sdev , sdev - > host_box . offset , msg - > msg_data ,
msg - > msg_size ) ;
snd_sof_dsp_write ( sdev , HDA_DSP_BAR , CNL_DSP_REG_HIPCIDR ,
2019-06-03 11:20:25 -05:00
CNL_DSP_REG_HIPCIDR_BUSY ) ;
2019-04-12 11:08:58 -05:00
return 0 ;
}
2019-04-30 18:09:34 -05:00
static void cnl_ipc_dump ( struct snd_sof_dev * sdev )
{
u32 hipcctl ;
u32 hipcida ;
u32 hipctdr ;
/* read IPC status */
hipcida = snd_sof_dsp_read ( sdev , HDA_DSP_BAR , CNL_DSP_REG_HIPCIDA ) ;
hipcctl = snd_sof_dsp_read ( sdev , HDA_DSP_BAR , CNL_DSP_REG_HIPCCTL ) ;
hipctdr = snd_sof_dsp_read ( sdev , HDA_DSP_BAR , CNL_DSP_REG_HIPCTDR ) ;
/* dump the IPC regs */
/* TODO: parse the raw msg */
dev_err ( sdev - > dev ,
" error: host status 0x%8.8x dsp status 0x%8.8x mask 0x%8.8x \n " ,
hipcida , hipctdr , hipcctl ) ;
}
2019-04-12 11:08:58 -05:00
/* cannonlake ops */
const struct snd_sof_dsp_ops sof_cnl_ops = {
/* probe and remove */
. probe = hda_dsp_probe ,
. remove = hda_dsp_remove ,
/* Register IO */
. write = sof_io_write ,
. read = sof_io_read ,
. write64 = sof_io_write64 ,
. read64 = sof_io_read64 ,
/* Block IO */
. block_read = sof_block_read ,
. block_write = sof_block_write ,
/* doorbell */
. irq_handler = hda_dsp_ipc_irq_handler ,
. irq_thread = cnl_ipc_irq_thread ,
/* ipc */
. send_msg = cnl_ipc_send_msg ,
. fw_ready = hda_dsp_ipc_fw_ready ,
. ipc_msg_data = hda_ipc_msg_data ,
. ipc_pcm_params = hda_ipc_pcm_params ,
/* debug */
. debug_map = cnl_dsp_debugfs ,
. debug_map_count = ARRAY_SIZE ( cnl_dsp_debugfs ) ,
. dbg_dump = hda_dsp_dump ,
2019-04-30 18:09:34 -05:00
. ipc_dump = cnl_ipc_dump ,
2019-04-12 11:08:58 -05:00
/* stream callbacks */
. pcm_open = hda_dsp_pcm_open ,
. pcm_close = hda_dsp_pcm_close ,
. pcm_hw_params = hda_dsp_pcm_hw_params ,
. pcm_trigger = hda_dsp_pcm_trigger ,
2019-04-30 18:09:19 -05:00
. pcm_pointer = hda_dsp_pcm_pointer ,
2019-04-12 11:08:58 -05:00
/* firmware loading */
. load_firmware = snd_sof_load_firmware_raw ,
/* pre/post fw run */
. pre_fw_run = hda_dsp_pre_fw_run ,
. post_fw_run = hda_dsp_post_fw_run ,
/* dsp core power up/down */
. core_power_up = hda_dsp_enable_core ,
. core_power_down = hda_dsp_core_reset_power_down ,
/* firmware run */
. run = hda_dsp_cl_boot_firmware ,
/* trace callback */
. trace_init = hda_dsp_trace_init ,
. trace_release = hda_dsp_trace_release ,
. trace_trigger = hda_dsp_trace_trigger ,
/* DAI drivers */
. drv = skl_dai ,
. num_drv = SOF_SKL_NUM_DAIS ,
/* PM */
. suspend = hda_dsp_suspend ,
. resume = hda_dsp_resume ,
. runtime_suspend = hda_dsp_runtime_suspend ,
. runtime_resume = hda_dsp_runtime_resume ,
2019-04-30 18:09:31 -05:00
. set_hw_params_upon_resume = hda_dsp_set_hw_params_upon_resume ,
2019-04-12 11:08:58 -05:00
} ;
EXPORT_SYMBOL ( sof_cnl_ops ) ;
const struct sof_intel_dsp_desc cnl_chip_info = {
/* Cannonlake */
. cores_num = 4 ,
. init_core_mask = 1 ,
. cores_mask = HDA_DSP_CORE_MASK ( 0 ) |
HDA_DSP_CORE_MASK ( 1 ) |
HDA_DSP_CORE_MASK ( 2 ) |
HDA_DSP_CORE_MASK ( 3 ) ,
. ipc_req = CNL_DSP_REG_HIPCIDR ,
. ipc_req_mask = CNL_DSP_REG_HIPCIDR_BUSY ,
. ipc_ack = CNL_DSP_REG_HIPCIDA ,
. ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE ,
. ipc_ctl = CNL_DSP_REG_HIPCCTL ,
. rom_init_timeout = 300 ,
2019-04-30 18:09:21 -05:00
. ssp_count = CNL_SSP_COUNT ,
. ssp_base_offset = CNL_SSP_BASE_OFFSET ,
2019-04-12 11:08:58 -05:00
} ;
EXPORT_SYMBOL ( cnl_chip_info ) ;
2019-05-09 15:10:27 -05:00
const struct sof_intel_dsp_desc icl_chip_info = {
/* Icelake */
. cores_num = 4 ,
. init_core_mask = 1 ,
. cores_mask = HDA_DSP_CORE_MASK ( 0 ) |
HDA_DSP_CORE_MASK ( 1 ) |
HDA_DSP_CORE_MASK ( 2 ) |
HDA_DSP_CORE_MASK ( 3 ) ,
. ipc_req = CNL_DSP_REG_HIPCIDR ,
. ipc_req_mask = CNL_DSP_REG_HIPCIDR_BUSY ,
. ipc_ack = CNL_DSP_REG_HIPCIDA ,
. ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE ,
. ipc_ctl = CNL_DSP_REG_HIPCCTL ,
. rom_init_timeout = 300 ,
. ssp_count = ICL_SSP_COUNT ,
. ssp_base_offset = CNL_SSP_BASE_OFFSET ,
} ;
EXPORT_SYMBOL ( icl_chip_info ) ;