[PATCH 00/14] Add Renoir ACP driver
This adds an ASoC driver for the ACP (Audio CoProcessor) block on AMD Renoir APUs.
The full series can also be pulled from here: https://cgit.freedesktop.org/~agd5f/linux/log/?h=renoir-acp
Vijendar Mukunda (14): ASoC: amd: add Renoir ACP3x IP register header ASoC: amd: add Renoir ACP PCI driver ASoC: amd: add acp init/de-init functions ASoC: amd: create acp3x pdm platform device ASoC: amd: add ACP3x PDM platform driver ASoC: amd: irq handler changes for ACP3x PDM dma driver ASoC: amd: add acp3x pdm driver dma ops ASoC: amd: add ACP PDM DMA driver dai ops ASoC: amd: add Renoir ACP PCI driver PM ops ASoC: amd: add ACP PDM DMA driver pm ops ASoC: amd: enable Renoir acp3x drivers build ASoC: amd: create platform devices for Renoir ASoC: amd: RN machine driver using dmic ASoC: amd: enable build for RN machine driver
sound/soc/amd/Kconfig | 13 + sound/soc/amd/Makefile | 1 + sound/soc/amd/renoir/Makefile | 7 + sound/soc/amd/renoir/acp3x-pdm-dma.c | 534 +++++++++++++++++++++ sound/soc/amd/renoir/acp3x-rn.c | 112 +++++ sound/soc/amd/renoir/rn-pci-acp3x.c | 346 +++++++++++++ sound/soc/amd/renoir/rn_acp3x.h | 86 ++++ sound/soc/amd/renoir/rn_chip_offset_byte.h | 349 ++++++++++++++ 8 files changed, 1448 insertions(+) create mode 100644 sound/soc/amd/renoir/Makefile create mode 100644 sound/soc/amd/renoir/acp3x-pdm-dma.c create mode 100644 sound/soc/amd/renoir/acp3x-rn.c create mode 100644 sound/soc/amd/renoir/rn-pci-acp3x.c create mode 100644 sound/soc/amd/renoir/rn_acp3x.h create mode 100644 sound/soc/amd/renoir/rn_chip_offset_byte.h
From: Vijendar Mukunda Vijendar.Mukunda@amd.com
Add register header for ACP3x IP in Renoir platform.
Signed-off-by: Vijendar Mukunda Vijendar.Mukunda@amd.com Signed-off-by: Alex Deucher alexander.deucher@amd.com --- sound/soc/amd/renoir/rn_chip_offset_byte.h | 349 +++++++++++++++++++++ 1 file changed, 349 insertions(+) create mode 100644 sound/soc/amd/renoir/rn_chip_offset_byte.h
diff --git a/sound/soc/amd/renoir/rn_chip_offset_byte.h b/sound/soc/amd/renoir/rn_chip_offset_byte.h new file mode 100644 index 000000000000..d20d967b5ff9 --- /dev/null +++ b/sound/soc/amd/renoir/rn_chip_offset_byte.h @@ -0,0 +1,349 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * AMD ACP 3.1 Register Documentation + * + * Copyright 2020 Advanced Micro Devices, Inc. + */ + +#ifndef _rn_OFFSET_HEADER +#define _rn_OFFSET_HEADER +// Registers from ACP_DMA block + +#define ACP_DMA_CNTL_0 0x1240000 +#define ACP_DMA_CNTL_1 0x1240004 +#define ACP_DMA_CNTL_2 0x1240008 +#define ACP_DMA_CNTL_3 0x124000C +#define ACP_DMA_CNTL_4 0x1240010 +#define ACP_DMA_CNTL_5 0x1240014 +#define ACP_DMA_CNTL_6 0x1240018 +#define ACP_DMA_CNTL_7 0x124001C +#define ACP_DMA_DSCR_STRT_IDX_0 0x1240020 +#define ACP_DMA_DSCR_STRT_IDX_1 0x1240024 +#define ACP_DMA_DSCR_STRT_IDX_2 0x1240028 +#define ACP_DMA_DSCR_STRT_IDX_3 0x124002C +#define ACP_DMA_DSCR_STRT_IDX_4 0x1240030 +#define ACP_DMA_DSCR_STRT_IDX_5 0x1240034 +#define ACP_DMA_DSCR_STRT_IDX_6 0x1240038 +#define ACP_DMA_DSCR_STRT_IDX_7 0x124003C +#define ACP_DMA_DSCR_CNT_0 0x1240040 +#define ACP_DMA_DSCR_CNT_1 0x1240044 +#define ACP_DMA_DSCR_CNT_2 0x1240048 +#define ACP_DMA_DSCR_CNT_3 0x124004C +#define ACP_DMA_DSCR_CNT_4 0x1240050 +#define ACP_DMA_DSCR_CNT_5 0x1240054 +#define ACP_DMA_DSCR_CNT_6 0x1240058 +#define ACP_DMA_DSCR_CNT_7 0x124005C +#define ACP_DMA_PRIO_0 0x1240060 +#define ACP_DMA_PRIO_1 0x1240064 +#define ACP_DMA_PRIO_2 0x1240068 +#define ACP_DMA_PRIO_3 0x124006C +#define ACP_DMA_PRIO_4 0x1240070 +#define ACP_DMA_PRIO_5 0x1240074 +#define ACP_DMA_PRIO_6 0x1240078 +#define ACP_DMA_PRIO_7 0x124007C +#define ACP_DMA_CUR_DSCR_0 0x1240080 +#define ACP_DMA_CUR_DSCR_1 0x1240084 +#define ACP_DMA_CUR_DSCR_2 0x1240088 +#define ACP_DMA_CUR_DSCR_3 0x124008C +#define ACP_DMA_CUR_DSCR_4 0x1240090 +#define ACP_DMA_CUR_DSCR_5 0x1240094 +#define ACP_DMA_CUR_DSCR_6 0x1240098 +#define ACP_DMA_CUR_DSCR_7 0x124009C +#define ACP_DMA_CUR_TRANS_CNT_0 0x12400A0 +#define ACP_DMA_CUR_TRANS_CNT_1 0x12400A4 +#define ACP_DMA_CUR_TRANS_CNT_2 0x12400A8 +#define ACP_DMA_CUR_TRANS_CNT_3 0x12400AC +#define ACP_DMA_CUR_TRANS_CNT_4 0x12400B0 +#define ACP_DMA_CUR_TRANS_CNT_5 0x12400B4 +#define ACP_DMA_CUR_TRANS_CNT_6 0x12400B8 +#define ACP_DMA_CUR_TRANS_CNT_7 0x12400BC +#define ACP_DMA_ERR_STS_0 0x12400C0 +#define ACP_DMA_ERR_STS_1 0x12400C4 +#define ACP_DMA_ERR_STS_2 0x12400C8 +#define ACP_DMA_ERR_STS_3 0x12400CC +#define ACP_DMA_ERR_STS_4 0x12400D0 +#define ACP_DMA_ERR_STS_5 0x12400D4 +#define ACP_DMA_ERR_STS_6 0x12400D8 +#define ACP_DMA_ERR_STS_7 0x12400DC +#define ACP_DMA_DESC_BASE_ADDR 0x12400E0 +#define ACP_DMA_DESC_MAX_NUM_DSCR 0x12400E4 +#define ACP_DMA_CH_STS 0x12400E8 +#define ACP_DMA_CH_GROUP 0x12400EC +#define ACP_DMA_CH_RST_STS 0x12400F0 + +// Registers from ACP_AXI2AXIATU block + +#define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_1 0x1240C00 +#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_1 0x1240C04 +#define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_2 0x1240C08 +#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_2 0x1240C0C +#define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_3 0x1240C10 +#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_3 0x1240C14 +#define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_4 0x1240C18 +#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_4 0x1240C1C +#define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_5 0x1240C20 +#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_5 0x1240C24 +#define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_6 0x1240C28 +#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_6 0x1240C2C +#define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_7 0x1240C30 +#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_7 0x1240C34 +#define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_8 0x1240C38 +#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_8 0x1240C3C +#define ACPAXI2AXI_ATU_CTRL 0x1240C40 + +// Registers from ACP_CLKRST block + +#define ACP_SOFT_RESET 0x1241000 +#define ACP_CONTROL 0x1241004 +#define ACP_STATUS 0x1241008 +#define ACP_DYNAMIC_CG_MASTER_CONTROL 0x1241010 + +// Registers from ACP_MISC block + +#define ACP_EXTERNAL_INTR_ENB 0x1241800 +#define ACP_EXTERNAL_INTR_CNTL 0x1241804 +#define ACP_EXTERNAL_INTR_STAT 0x1241808 +#define ACP_PGMEM_CTRL 0x12418C0 +#define ACP_ERROR_STATUS 0x12418C4 +#define ACP_SW_I2S_ERROR_REASON 0x12418C8 +#define ACP_MEM_PG_STS 0x12418CC + +// Registers from ACP_PGFSM block + +#define ACP_I2S_PIN_CONFIG 0x1241400 +#define ACP_PAD_PULLUP_PULLDOWN_CTRL 0x1241404 +#define ACP_PAD_DRIVE_STRENGTH_CTRL 0x1241408 +#define ACP_SW_PAD_KEEPER_EN 0x124140C +#define ACP_PGFSM_CONTROL 0x124141C +#define ACP_PGFSM_STATUS 0x1241420 +#define ACP_CLKMUX_SEL 0x1241424 +#define ACP_DEVICE_STATE 0x1241428 +#define AZ_DEVICE_STATE 0x124142C +#define ACP_INTR_URGENCY_TIMER 0x1241430 +#define AZ_INTR_URGENCY_TIMER 0x1241434 + +// Registers from ACP_SCRATCH block + +#define ACP_SCRATCH_REG_0 0x1250000 +#define ACP_SCRATCH_REG_1 0x1250004 +#define ACP_SCRATCH_REG_2 0x1250008 +#define ACP_SCRATCH_REG_3 0x125000C +#define ACP_SCRATCH_REG_4 0x1250010 +#define ACP_SCRATCH_REG_5 0x1250014 +#define ACP_SCRATCH_REG_6 0x1250018 +#define ACP_SCRATCH_REG_7 0x125001C +#define ACP_SCRATCH_REG_8 0x1250020 +#define ACP_SCRATCH_REG_9 0x1250024 +#define ACP_SCRATCH_REG_10 0x1250028 +#define ACP_SCRATCH_REG_11 0x125002C +#define ACP_SCRATCH_REG_12 0x1250030 +#define ACP_SCRATCH_REG_13 0x1250034 +#define ACP_SCRATCH_REG_14 0x1250038 +#define ACP_SCRATCH_REG_15 0x125003C +#define ACP_SCRATCH_REG_16 0x1250040 +#define ACP_SCRATCH_REG_17 0x1250044 +#define ACP_SCRATCH_REG_18 0x1250048 +#define ACP_SCRATCH_REG_19 0x125004C +#define ACP_SCRATCH_REG_20 0x1250050 +#define ACP_SCRATCH_REG_21 0x1250054 +#define ACP_SCRATCH_REG_22 0x1250058 +#define ACP_SCRATCH_REG_23 0x125005C +#define ACP_SCRATCH_REG_24 0x1250060 +#define ACP_SCRATCH_REG_25 0x1250064 +#define ACP_SCRATCH_REG_26 0x1250068 +#define ACP_SCRATCH_REG_27 0x125006C +#define ACP_SCRATCH_REG_28 0x1250070 +#define ACP_SCRATCH_REG_29 0x1250074 +#define ACP_SCRATCH_REG_30 0x1250078 +#define ACP_SCRATCH_REG_31 0x125007C +#define ACP_SCRATCH_REG_32 0x1250080 +#define ACP_SCRATCH_REG_33 0x1250084 +#define ACP_SCRATCH_REG_34 0x1250088 +#define ACP_SCRATCH_REG_35 0x125008C +#define ACP_SCRATCH_REG_36 0x1250090 +#define ACP_SCRATCH_REG_37 0x1250094 +#define ACP_SCRATCH_REG_38 0x1250098 +#define ACP_SCRATCH_REG_39 0x125009C +#define ACP_SCRATCH_REG_40 0x12500A0 +#define ACP_SCRATCH_REG_41 0x12500A4 +#define ACP_SCRATCH_REG_42 0x12500A8 +#define ACP_SCRATCH_REG_43 0x12500AC +#define ACP_SCRATCH_REG_44 0x12500B0 +#define ACP_SCRATCH_REG_45 0x12500B4 +#define ACP_SCRATCH_REG_46 0x12500B8 +#define ACP_SCRATCH_REG_47 0x12500BC +#define ACP_SCRATCH_REG_48 0x12500C0 +#define ACP_SCRATCH_REG_49 0x12500C4 +#define ACP_SCRATCH_REG_50 0x12500C8 +#define ACP_SCRATCH_REG_51 0x12500CC +#define ACP_SCRATCH_REG_52 0x12500D0 +#define ACP_SCRATCH_REG_53 0x12500D4 +#define ACP_SCRATCH_REG_54 0x12500D8 +#define ACP_SCRATCH_REG_55 0x12500DC +#define ACP_SCRATCH_REG_56 0x12500E0 +#define ACP_SCRATCH_REG_57 0x12500E4 +#define ACP_SCRATCH_REG_58 0x12500E8 +#define ACP_SCRATCH_REG_59 0x12500EC +#define ACP_SCRATCH_REG_60 0x12500F0 +#define ACP_SCRATCH_REG_61 0x12500F4 +#define ACP_SCRATCH_REG_62 0x12500F8 +#define ACP_SCRATCH_REG_63 0x12500FC +#define ACP_SCRATCH_REG_64 0x1250100 +#define ACP_SCRATCH_REG_65 0x1250104 +#define ACP_SCRATCH_REG_66 0x1250108 +#define ACP_SCRATCH_REG_67 0x125010C +#define ACP_SCRATCH_REG_68 0x1250110 +#define ACP_SCRATCH_REG_69 0x1250114 +#define ACP_SCRATCH_REG_70 0x1250118 +#define ACP_SCRATCH_REG_71 0x125011C +#define ACP_SCRATCH_REG_72 0x1250120 +#define ACP_SCRATCH_REG_73 0x1250124 +#define ACP_SCRATCH_REG_74 0x1250128 +#define ACP_SCRATCH_REG_75 0x125012C +#define ACP_SCRATCH_REG_76 0x1250130 +#define ACP_SCRATCH_REG_77 0x1250134 +#define ACP_SCRATCH_REG_78 0x1250138 +#define ACP_SCRATCH_REG_79 0x125013C +#define ACP_SCRATCH_REG_80 0x1250140 +#define ACP_SCRATCH_REG_81 0x1250144 +#define ACP_SCRATCH_REG_82 0x1250148 +#define ACP_SCRATCH_REG_83 0x125014C +#define ACP_SCRATCH_REG_84 0x1250150 +#define ACP_SCRATCH_REG_85 0x1250154 +#define ACP_SCRATCH_REG_86 0x1250158 +#define ACP_SCRATCH_REG_87 0x125015C +#define ACP_SCRATCH_REG_88 0x1250160 +#define ACP_SCRATCH_REG_89 0x1250164 +#define ACP_SCRATCH_REG_90 0x1250168 +#define ACP_SCRATCH_REG_91 0x125016C +#define ACP_SCRATCH_REG_92 0x1250170 +#define ACP_SCRATCH_REG_93 0x1250174 +#define ACP_SCRATCH_REG_94 0x1250178 +#define ACP_SCRATCH_REG_95 0x125017C +#define ACP_SCRATCH_REG_96 0x1250180 +#define ACP_SCRATCH_REG_97 0x1250184 +#define ACP_SCRATCH_REG_98 0x1250188 +#define ACP_SCRATCH_REG_99 0x125018C +#define ACP_SCRATCH_REG_100 0x1250190 +#define ACP_SCRATCH_REG_101 0x1250194 +#define ACP_SCRATCH_REG_102 0x1250198 +#define ACP_SCRATCH_REG_103 0x125019C +#define ACP_SCRATCH_REG_104 0x12501A0 +#define ACP_SCRATCH_REG_105 0x12501A4 +#define ACP_SCRATCH_REG_106 0x12501A8 +#define ACP_SCRATCH_REG_107 0x12501AC +#define ACP_SCRATCH_REG_108 0x12501B0 +#define ACP_SCRATCH_REG_109 0x12501B4 +#define ACP_SCRATCH_REG_110 0x12501B8 +#define ACP_SCRATCH_REG_111 0x12501BC +#define ACP_SCRATCH_REG_112 0x12501C0 +#define ACP_SCRATCH_REG_113 0x12501C4 +#define ACP_SCRATCH_REG_114 0x12501C8 +#define ACP_SCRATCH_REG_115 0x12501CC +#define ACP_SCRATCH_REG_116 0x12501D0 +#define ACP_SCRATCH_REG_117 0x12501D4 +#define ACP_SCRATCH_REG_118 0x12501D8 +#define ACP_SCRATCH_REG_119 0x12501DC +#define ACP_SCRATCH_REG_120 0x12501E0 +#define ACP_SCRATCH_REG_121 0x12501E4 +#define ACP_SCRATCH_REG_122 0x12501E8 +#define ACP_SCRATCH_REG_123 0x12501EC +#define ACP_SCRATCH_REG_124 0x12501F0 +#define ACP_SCRATCH_REG_125 0x12501F4 +#define ACP_SCRATCH_REG_126 0x12501F8 +#define ACP_SCRATCH_REG_127 0x12501FC +#define ACP_SCRATCH_REG_128 0x1250200 + +// Registers from ACP_AUDIO_BUFFERS block + +#define ACP_I2S_RX_RINGBUFADDR 0x1242000 +#define ACP_I2S_RX_RINGBUFSIZE 0x1242004 +#define ACP_I2S_RX_LINKPOSITIONCNTR 0x1242008 +#define ACP_I2S_RX_FIFOADDR 0x124200C +#define ACP_I2S_RX_FIFOSIZE 0x1242010 +#define ACP_I2S_RX_DMA_SIZE 0x1242014 +#define ACP_I2S_RX_LINEARPOSITIONCNTR_HIGH 0x1242018 +#define ACP_I2S_RX_LINEARPOSITIONCNTR_LOW 0x124201C +#define ACP_I2S_RX_INTR_WATERMARK_SIZE 0x1242020 +#define ACP_I2S_TX_RINGBUFADDR 0x1242024 +#define ACP_I2S_TX_RINGBUFSIZE 0x1242028 +#define ACP_I2S_TX_LINKPOSITIONCNTR 0x124202C +#define ACP_I2S_TX_FIFOADDR 0x1242030 +#define ACP_I2S_TX_FIFOSIZE 0x1242034 +#define ACP_I2S_TX_DMA_SIZE 0x1242038 +#define ACP_I2S_TX_LINEARPOSITIONCNTR_HIGH 0x124203C +#define ACP_I2S_TX_LINEARPOSITIONCNTR_LOW 0x1242040 +#define ACP_I2S_TX_INTR_WATERMARK_SIZE 0x1242044 +#define ACP_BT_RX_RINGBUFADDR 0x1242048 +#define ACP_BT_RX_RINGBUFSIZE 0x124204C +#define ACP_BT_RX_LINKPOSITIONCNTR 0x1242050 +#define ACP_BT_RX_FIFOADDR 0x1242054 +#define ACP_BT_RX_FIFOSIZE 0x1242058 +#define ACP_BT_RX_DMA_SIZE 0x124205C +#define ACP_BT_RX_LINEARPOSITIONCNTR_HIGH 0x1242060 +#define ACP_BT_RX_LINEARPOSITIONCNTR_LOW 0x1242064 +#define ACP_BT_RX_INTR_WATERMARK_SIZE 0x1242068 +#define ACP_BT_TX_RINGBUFADDR 0x124206C +#define ACP_BT_TX_RINGBUFSIZE 0x1242070 +#define ACP_BT_TX_LINKPOSITIONCNTR 0x1242074 +#define ACP_BT_TX_FIFOADDR 0x1242078 +#define ACP_BT_TX_FIFOSIZE 0x124207C +#define ACP_BT_TX_DMA_SIZE 0x1242080 +#define ACP_BT_TX_LINEARPOSITIONCNTR_HIGH 0x1242084 +#define ACP_BT_TX_LINEARPOSITIONCNTR_LOW 0x1242088 +#define ACP_BT_TX_INTR_WATERMARK_SIZE 0x124208C +#define ACP_HS_RX_RINGBUFADDR 0x1242090 +#define ACP_HS_RX_RINGBUFSIZE 0x1242094 +#define ACP_HS_RX_LINKPOSITIONCNTR 0x1242098 +#define ACP_HS_RX_FIFOADDR 0x124209C +#define ACP_HS_RX_FIFOSIZE 0x12420A0 +#define ACP_HS_RX_DMA_SIZE 0x12420A4 +#define ACP_HS_RX_LINEARPOSITIONCNTR_HIGH 0x12420A8 +#define ACP_HS_RX_LINEARPOSITIONCNTR_LOW 0x12420AC +#define ACP_HS_RX_INTR_WATERMARK_SIZE 0x12420B0 +#define ACP_HS_TX_RINGBUFADDR 0x12420B4 +#define ACP_HS_TX_RINGBUFSIZE 0x12420B8 +#define ACP_HS_TX_LINKPOSITIONCNTR 0x12420BC +#define ACP_HS_TX_FIFOADDR 0x12420C0 +#define ACP_HS_TX_FIFOSIZE 0x12420C4 +#define ACP_HS_TX_DMA_SIZE 0x12420C8 +#define ACP_HS_TX_LINEARPOSITIONCNTR_HIGH 0x12420CC +#define ACP_HS_TX_LINEARPOSITIONCNTR_LOW 0x12420D0 +#define ACP_HS_TX_INTR_WATERMARK_SIZE 0x12420D4 + +// Registers from ACP_I2S_TDM block + +#define ACP_I2STDM_IER 0x1242400 +#define ACP_I2STDM_IRER 0x1242404 +#define ACP_I2STDM_RXFRMT 0x1242408 +#define ACP_I2STDM_ITER 0x124240C +#define ACP_I2STDM_TXFRMT 0x1242410 + +// Registers from ACP_BT_TDM block + +#define ACP_BTTDM_IER 0x1242800 +#define ACP_BTTDM_IRER 0x1242804 +#define ACP_BTTDM_RXFRMT 0x1242808 +#define ACP_BTTDM_ITER 0x124280C +#define ACP_BTTDM_TXFRMT 0x1242810 + +// Registers from ACP_WOV block + +#define ACP_WOV_PDM_ENABLE 0x1242C04 +#define ACP_WOV_PDM_DMA_ENABLE 0x1242C08 +#define ACP_WOV_RX_RINGBUFADDR 0x1242C0C +#define ACP_WOV_RX_RINGBUFSIZE 0x1242C10 +#define ACP_WOV_RX_LINKPOSITIONCNTR 0x1242C14 +#define ACP_WOV_RX_LINEARPOSITIONCNTR_HIGH 0x1242C18 +#define ACP_WOV_RX_LINEARPOSITIONCNTR_LOW 0x1242C1C +#define ACP_WOV_RX_INTR_WATERMARK_SIZE 0x1242C20 +#define ACP_WOV_PDM_FIFO_FLUSH 0x1242C24 +#define ACP_WOV_PDM_NO_OF_CHANNELS 0x1242C28 +#define ACP_WOV_PDM_DECIMATION_FACTOR 0x1242C2C +#define ACP_WOV_PDM_VAD_CTRL 0x1242C30 +#define ACP_WOV_BUFFER_STATUS 0x1242C58 +#define ACP_WOV_MISC_CTRL 0x1242C5C +#define ACP_WOV_CLK_CTRL 0x1242C60 +#define ACP_PDM_VAD_DYNAMIC_CLK_GATING_EN 0x1242C64 +#define ACP_WOV_ERROR_STATUS_REGISTER 0x1242C68 +#endif
From: Vijendar Mukunda Vijendar.Mukunda@amd.com
ACP is a PCI audio device. This patch adds PCI driver to bind to this device and get PCI resources.
Signed-off-by: Vijendar Mukunda Vijendar.Mukunda@amd.com Signed-off-by: Alex Deucher alexander.deucher@amd.com --- sound/soc/amd/renoir/rn-pci-acp3x.c | 87 +++++++++++++++++++++++++++++ sound/soc/amd/renoir/rn_acp3x.h | 21 +++++++ 2 files changed, 108 insertions(+) create mode 100644 sound/soc/amd/renoir/rn-pci-acp3x.c create mode 100644 sound/soc/amd/renoir/rn_acp3x.h
diff --git a/sound/soc/amd/renoir/rn-pci-acp3x.c b/sound/soc/amd/renoir/rn-pci-acp3x.c new file mode 100644 index 000000000000..56b76e355cd4 --- /dev/null +++ b/sound/soc/amd/renoir/rn-pci-acp3x.c @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// AMD Renoir ACP PCI Driver +// +//Copyright 2020 Advanced Micro Devices, Inc. + +#include <linux/pci.h> +#include <linux/module.h> +#include <linux/io.h> + +#include "rn_acp3x.h" + +struct acp_dev_data { + void __iomem *acp_base; +}; + +static int snd_rn_acp_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) +{ + struct acp_dev_data *adata; + int ret; + u32 addr; + + if (pci_enable_device(pci)) { + dev_err(&pci->dev, "pci_enable_device failed\n"); + return -ENODEV; + } + + ret = pci_request_regions(pci, "AMD ACP3x audio"); + if (ret < 0) { + dev_err(&pci->dev, "pci_request_regions failed\n"); + goto disable_pci; + } + + adata = devm_kzalloc(&pci->dev, sizeof(struct acp_dev_data), + GFP_KERNEL); + if (!adata) { + ret = -ENOMEM; + goto release_regions; + } + + addr = pci_resource_start(pci, 0); + adata->acp_base = devm_ioremap(&pci->dev, addr, + pci_resource_len(pci, 0)); + if (!adata->acp_base) { + ret = -ENOMEM; + goto release_regions; + } + pci_set_master(pci); + pci_set_drvdata(pci, adata); + return 0; + +release_regions: + pci_release_regions(pci); +disable_pci: + pci_disable_device(pci); + + return ret; +} + +static void snd_rn_acp_remove(struct pci_dev *pci) +{ + pci_disable_msi(pci); + pci_release_regions(pci); + pci_disable_device(pci); +} + +static const struct pci_device_id snd_rn_acp_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_AMD, ACP_DEVICE_ID), + .class = PCI_CLASS_MULTIMEDIA_OTHER << 8, + .class_mask = 0xffffff }, + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, snd_rn_acp_ids); + +static struct pci_driver rn_acp_driver = { + .name = KBUILD_MODNAME, + .id_table = snd_rn_acp_ids, + .probe = snd_rn_acp_probe, + .remove = snd_rn_acp_remove, +}; + +module_pci_driver(rn_acp_driver); + +MODULE_AUTHOR("Vijendar.Mukunda@amd.com"); +MODULE_DESCRIPTION("AMD ACP Renoir PCI driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/amd/renoir/rn_acp3x.h b/sound/soc/amd/renoir/rn_acp3x.h new file mode 100644 index 000000000000..da5715759646 --- /dev/null +++ b/sound/soc/amd/renoir/rn_acp3x.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * AMD ALSA SoC PDM Driver + * + * Copyright 2020 Advanced Micro Devices, Inc. + */ + +#include "rn_chip_offset_byte.h" + +#define ACP_PHY_BASE_ADDRESS 0x1240000 +#define ACP_DEVICE_ID 0x15E2 + +static inline u32 rn_readl(void __iomem *base_addr) +{ + return readl(base_addr - ACP_PHY_BASE_ADDRESS); +} + +static inline void rn_writel(u32 val, void __iomem *base_addr) +{ + writel(val, base_addr - ACP_PHY_BASE_ADDRESS); +}
From: Vijendar Mukunda Vijendar.Mukunda@amd.com
Add Renoir ACP PCI driver init/deinit functions.
Signed-off-by: Vijendar Mukunda Vijendar.Mukunda@amd.com Signed-off-by: Alex Deucher alexander.deucher@amd.com --- sound/soc/amd/renoir/rn-pci-acp3x.c | 143 ++++++++++++++++++++++++++++ sound/soc/amd/renoir/rn_acp3x.h | 16 ++++ 2 files changed, 159 insertions(+)
diff --git a/sound/soc/amd/renoir/rn-pci-acp3x.c b/sound/soc/amd/renoir/rn-pci-acp3x.c index 56b76e355cd4..429813f6ba1c 100644 --- a/sound/soc/amd/renoir/rn-pci-acp3x.c +++ b/sound/soc/amd/renoir/rn-pci-acp3x.c @@ -7,13 +7,146 @@ #include <linux/pci.h> #include <linux/module.h> #include <linux/io.h> +#include <linux/delay.h>
#include "rn_acp3x.h"
+static int acp_power_gating; +module_param(acp_power_gating, int, 0644); +MODULE_PARM_DESC(acp_power_gating, "Enable acp power gating"); + struct acp_dev_data { void __iomem *acp_base; };
+static int rn_acp_power_on(void __iomem *acp_base) +{ + u32 val; + int timeout; + + val = rn_readl(acp_base + ACP_PGFSM_STATUS); + + if (val == 0) + return val; + + if ((val & ACP_PGFSM_STATUS_MASK) != + ACP_POWER_ON_IN_PROGRESS) + rn_writel(ACP_PGFSM_CNTL_POWER_ON_MASK, + acp_base + ACP_PGFSM_CONTROL); + timeout = 0; + while (++timeout < 500) { + val = rn_readl(acp_base + ACP_PGFSM_STATUS); + if (!val) + return 0; + udelay(1); + } + return -ETIMEDOUT; +} + +static int rn_acp_power_off(void __iomem *acp_base) +{ + u32 val; + int timeout; + + rn_writel(ACP_PGFSM_CNTL_POWER_OFF_MASK, + acp_base + ACP_PGFSM_CONTROL); + timeout = 0; + while (++timeout < 500) { + val = rn_readl(acp_base + ACP_PGFSM_STATUS); + if ((val & ACP_PGFSM_STATUS_MASK) == ACP_POWERED_OFF) + return 0; + udelay(1); + } + return -ETIMEDOUT; +} + +static int rn_acp_reset(void __iomem *acp_base) +{ + u32 val; + int timeout; + + rn_writel(1, acp_base + ACP_SOFT_RESET); + timeout = 0; + while (++timeout < 500) { + val = rn_readl(acp_base + ACP_SOFT_RESET); + if (val & ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK) + break; + cpu_relax(); + } + rn_writel(0, acp_base + ACP_SOFT_RESET); + timeout = 0; + while (++timeout < 500) { + val = rn_readl(acp_base + ACP_SOFT_RESET); + if (!val) + return 0; + cpu_relax(); + } + return -ETIMEDOUT; +} + +static void rn_acp_enable_interrupts(void __iomem *acp_base) +{ + u32 ext_intr_ctrl; + + rn_writel(0x01, acp_base + ACP_EXTERNAL_INTR_ENB); + ext_intr_ctrl = rn_readl(acp_base + ACP_EXTERNAL_INTR_CNTL); + ext_intr_ctrl |= ACP_ERROR_MASK; + rn_writel(ext_intr_ctrl, acp_base + ACP_EXTERNAL_INTR_CNTL); +} + +static void rn_acp_disable_interrupts(void __iomem *acp_base) +{ + rn_writel(ACP_EXT_INTR_STAT_CLEAR_MASK, acp_base + + ACP_EXTERNAL_INTR_STAT); + rn_writel(0x00, acp_base + ACP_EXTERNAL_INTR_ENB); +} + +static int rn_acp_init(void __iomem *acp_base) +{ + int ret; + + /* power on */ + ret = rn_acp_power_on(acp_base); + if (ret) { + pr_err("ACP power on failed\n"); + return ret; + } + rn_writel(0x01, acp_base + ACP_CONTROL); + /* Reset */ + ret = rn_acp_reset(acp_base); + if (ret) { + pr_err("ACP reset failed\n"); + return ret; + } + rn_writel(0x03, acp_base + ACP_CLKMUX_SEL); + rn_acp_enable_interrupts(acp_base); + return 0; +} + +static int rn_acp_deinit(void __iomem *acp_base) +{ + int ret; + + rn_acp_disable_interrupts(acp_base); + /* Reset */ + ret = rn_acp_reset(acp_base); + if (ret) { + pr_err("ACP reset failed\n"); + return ret; + } + rn_writel(0x00, acp_base + ACP_CLKMUX_SEL); + rn_writel(0x00, acp_base + ACP_CONTROL); + /* power off */ + if (acp_power_gating) { + ret = rn_acp_power_off(acp_base); + if (ret) { + pr_err("ACP power off failed\n"); + return ret; + } + } + return 0; +} + static int snd_rn_acp_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { @@ -48,6 +181,9 @@ static int snd_rn_acp_probe(struct pci_dev *pci, } pci_set_master(pci); pci_set_drvdata(pci, adata); + ret = rn_acp_init(adata->acp_base); + if (ret) + goto release_regions; return 0;
release_regions: @@ -60,6 +196,13 @@ static int snd_rn_acp_probe(struct pci_dev *pci,
static void snd_rn_acp_remove(struct pci_dev *pci) { + struct acp_dev_data *adata; + int ret; + + adata = pci_get_drvdata(pci); + ret = rn_acp_deinit(adata->acp_base); + if (ret) + dev_err(&pci->dev, "ACP de-init failed\n"); pci_disable_msi(pci); pci_release_regions(pci); pci_disable_device(pci); diff --git a/sound/soc/amd/renoir/rn_acp3x.h b/sound/soc/amd/renoir/rn_acp3x.h index da5715759646..ec2a85085163 100644 --- a/sound/soc/amd/renoir/rn_acp3x.h +++ b/sound/soc/amd/renoir/rn_acp3x.h @@ -9,6 +9,22 @@
#define ACP_PHY_BASE_ADDRESS 0x1240000 #define ACP_DEVICE_ID 0x15E2 +#define ACP_POWER_ON 0x00 +#define ACP_POWER_ON_IN_PROGRESS 0x01 +#define ACP_POWER_OFF 0x02 +#define ACP_POWER_OFF_IN_PROGRESS 0x03 +#define ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK 0x00010001 + +#define ACP_PGFSM_CNTL_POWER_ON_MASK 0x01 +#define ACP_PGFSM_CNTL_POWER_OFF_MASK 0x00 +#define ACP_PGFSM_STATUS_MASK 0x03 +#define ACP_POWERED_ON 0x00 +#define ACP_POWER_ON_IN_PROGRESS 0x01 +#define ACP_POWERED_OFF 0x02 +#define ACP_POWER_OFF_IN_PROGRESS 0x03 + +#define ACP_ERROR_MASK 0x20000000 +#define ACP_EXT_INTR_STAT_CLEAR_MASK 0xFFFFFFFF
static inline u32 rn_readl(void __iomem *base_addr) {
From: Vijendar Mukunda Vijendar.Mukunda@amd.com
ACP 3x IP has PDM decoder as one of IP blocks. Create a platform device for it, so that the PDM platform driver can be bound to this device. Pass PCI resources like MMIO, irq to this platform device.
Signed-off-by: Vijendar Mukunda Vijendar.Mukunda@amd.com Signed-off-by: Alex Deucher alexander.deucher@amd.com --- sound/soc/amd/renoir/rn-pci-acp3x.c | 61 ++++++++++++++++++++++++++++- sound/soc/amd/renoir/rn_acp3x.h | 3 ++ 2 files changed, 62 insertions(+), 2 deletions(-)
diff --git a/sound/soc/amd/renoir/rn-pci-acp3x.c b/sound/soc/amd/renoir/rn-pci-acp3x.c index 429813f6ba1c..362409ef0d85 100644 --- a/sound/soc/amd/renoir/rn-pci-acp3x.c +++ b/sound/soc/amd/renoir/rn-pci-acp3x.c @@ -8,6 +8,8 @@ #include <linux/module.h> #include <linux/io.h> #include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/interrupt.h>
#include "rn_acp3x.h"
@@ -17,6 +19,8 @@ MODULE_PARM_DESC(acp_power_gating, "Enable acp power gating");
struct acp_dev_data { void __iomem *acp_base; + struct resource *res; + struct platform_device *pdev; };
static int rn_acp_power_on(void __iomem *acp_base) @@ -151,6 +155,8 @@ static int snd_rn_acp_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { struct acp_dev_data *adata; + struct platform_device_info pdevinfo; + unsigned int irqflags; int ret; u32 addr;
@@ -172,20 +178,70 @@ static int snd_rn_acp_probe(struct pci_dev *pci, goto release_regions; }
+ /* check for msi interrupt support */ + ret = pci_enable_msi(pci); + if (ret) + /* msi is not enabled */ + irqflags = IRQF_SHARED; + else + /* msi is enabled */ + irqflags = 0; + addr = pci_resource_start(pci, 0); adata->acp_base = devm_ioremap(&pci->dev, addr, pci_resource_len(pci, 0)); if (!adata->acp_base) { ret = -ENOMEM; - goto release_regions; + goto disable_msi; } pci_set_master(pci); pci_set_drvdata(pci, adata); ret = rn_acp_init(adata->acp_base); if (ret) - goto release_regions; + goto disable_msi; + + adata->res = devm_kzalloc(&pci->dev, + sizeof(struct resource) * 2, + GFP_KERNEL); + if (!adata->res) { + ret = -ENOMEM; + goto de_init; + } + + adata->res[0].name = "acp_pdm_iomem"; + adata->res[0].flags = IORESOURCE_MEM; + adata->res[0].start = addr; + adata->res[0].end = addr + (ACP_REG_END - ACP_REG_START); + adata->res[1].name = "acp_pdm_irq"; + adata->res[1].flags = IORESOURCE_IRQ; + adata->res[1].start = pci->irq; + adata->res[1].end = pci->irq; + + memset(&pdevinfo, 0, sizeof(pdevinfo)); + pdevinfo.name = "acp_rn_pdm_dma"; + pdevinfo.id = 0; + pdevinfo.parent = &pci->dev; + pdevinfo.num_res = 2; + pdevinfo.res = adata->res; + pdevinfo.data = &irqflags; + pdevinfo.size_data = sizeof(irqflags); + + adata->pdev = platform_device_register_full(&pdevinfo); + if (IS_ERR(adata->pdev)) { + dev_err(&pci->dev, "cannot register %s device\n", + pdevinfo.name); + ret = PTR_ERR(adata->pdev); + goto unregister_devs; + } return 0;
+unregister_devs: + platform_device_unregister(adata->pdev); +de_init: + if (rn_acp_deinit(adata->acp_base)) + dev_err(&pci->dev, "ACP de-init failed\n"); +disable_msi: + pci_disable_msi(pci); release_regions: pci_release_regions(pci); disable_pci: @@ -200,6 +256,7 @@ static void snd_rn_acp_remove(struct pci_dev *pci) int ret;
adata = pci_get_drvdata(pci); + platform_device_unregister(adata->pdev); ret = rn_acp_deinit(adata->acp_base); if (ret) dev_err(&pci->dev, "ACP de-init failed\n"); diff --git a/sound/soc/amd/renoir/rn_acp3x.h b/sound/soc/amd/renoir/rn_acp3x.h index ec2a85085163..5e4fd99397d5 100644 --- a/sound/soc/amd/renoir/rn_acp3x.h +++ b/sound/soc/amd/renoir/rn_acp3x.h @@ -8,6 +8,9 @@ #include "rn_chip_offset_byte.h"
#define ACP_PHY_BASE_ADDRESS 0x1240000 +#define ACP_REG_START 0x1240000 +#define ACP_REG_END 0x1250200 + #define ACP_DEVICE_ID 0x15E2 #define ACP_POWER_ON 0x00 #define ACP_POWER_ON_IN_PROGRESS 0x01
From: Vijendar Mukunda Vijendar.Mukunda@amd.com
PDM platform driver binds to the platform device created by ACP3x PCI device. PDM driver registers ALSA DMA and CPU DAI components with ASoC framework.
Signed-off-by: Vijendar Mukunda Vijendar.Mukunda@amd.com Signed-off-by: Alex Deucher alexander.deucher@amd.com --- sound/soc/amd/renoir/acp3x-pdm-dma.c | 101 +++++++++++++++++++++++++++ sound/soc/amd/renoir/rn_acp3x.h | 5 ++ 2 files changed, 106 insertions(+) create mode 100644 sound/soc/amd/renoir/acp3x-pdm-dma.c
diff --git a/sound/soc/amd/renoir/acp3x-pdm-dma.c b/sound/soc/amd/renoir/acp3x-pdm-dma.c new file mode 100644 index 000000000000..680b2505d65d --- /dev/null +++ b/sound/soc/amd/renoir/acp3x-pdm-dma.c @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// AMD ALSA SoC PDM Driver +// +//Copyright 2020 Advanced Micro Devices, Inc. + +#include <linux/platform_device.h> +#include <linux/module.h> +#include <linux/err.h> +#include <linux/io.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-dai.h> + +#include "rn_acp3x.h" + +#define DRV_NAME "acp_rn_pdm_dma" + +static struct snd_soc_dai_ops acp_pdm_dai_ops = { + .hw_params = NULL, + .trigger = NULL, +}; + +static struct snd_soc_dai_driver acp_pdm_dai_driver = { + .capture = { + .rates = SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, + .channels_min = 2, + .channels_max = 2, + .rate_min = 48000, + .rate_max = 48000, + }, + .ops = &acp_pdm_dai_ops, +}; + +static const struct snd_soc_component_driver acp_pdm_component = { + .name = DRV_NAME, +}; + +static int acp_pdm_audio_probe(struct platform_device *pdev) +{ + struct resource *res; + struct pdm_dev_data *adata; + unsigned int irqflags; + int status; + + if (!pdev->dev.platform_data) { + dev_err(&pdev->dev, "platform_data not retrieved\n"); + return -ENODEV; + } + irqflags = *((unsigned int *)(pdev->dev.platform_data)); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "IORESOURCE_MEM FAILED\n"); + return -ENODEV; + } + + adata = devm_kzalloc(&pdev->dev, sizeof(*adata), GFP_KERNEL); + if (!adata) + return -ENOMEM; + + adata->acp_base = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + if (!adata->acp_base) + return -ENOMEM; + + adata->capture_stream = NULL; + + dev_set_drvdata(&pdev->dev, adata); + status = devm_snd_soc_register_component(&pdev->dev, + &acp_pdm_component, + &acp_pdm_dai_driver, 1); + if (status) { + dev_err(&pdev->dev, "Fail to register acp pdm dai\n"); + + return -ENODEV; + } + return 0; +} + +static int acp_pdm_audio_remove(struct platform_device *pdev) +{ + return 0; +} + +static struct platform_driver acp_pdm_dma_driver = { + .probe = acp_pdm_audio_probe, + .remove = acp_pdm_audio_remove, + .driver = { + .name = "acp_rn_pdm_dma", + }, +}; + +module_platform_driver(acp_pdm_dma_driver); + +MODULE_AUTHOR("Vijendar.Mukunda@amd.com"); +MODULE_DESCRIPTION("AMD ACP3x Renior PDM Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRV_NAME); diff --git a/sound/soc/amd/renoir/rn_acp3x.h b/sound/soc/amd/renoir/rn_acp3x.h index 5e4fd99397d5..0b450882c6c4 100644 --- a/sound/soc/amd/renoir/rn_acp3x.h +++ b/sound/soc/amd/renoir/rn_acp3x.h @@ -29,6 +29,11 @@ #define ACP_ERROR_MASK 0x20000000 #define ACP_EXT_INTR_STAT_CLEAR_MASK 0xFFFFFFFF
+struct pdm_dev_data { + void __iomem *acp_base; + struct snd_pcm_substream *capture_stream; +}; + static inline u32 rn_readl(void __iomem *base_addr) { return readl(base_addr - ACP_PHY_BASE_ADDRESS);
+static struct snd_soc_dai_ops acp_pdm_dai_ops = {
- .hw_params = NULL,
- .trigger = NULL,
+};
doesn't seem very useful? can you remove this pdm_dai_ops?
+static struct snd_soc_dai_driver acp_pdm_dai_driver = {
- .capture = {
.rates = SNDRV_PCM_RATE_48000,
.formats = SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 2,
.channels_max = 2,
.rate_min = 48000,
.rate_max = 48000,
- },
- .ops = &acp_pdm_dai_ops,
+};
+static const struct snd_soc_component_driver acp_pdm_component = {
- .name = DRV_NAME,
+};
+static int acp_pdm_audio_probe(struct platform_device *pdev) +{
- struct resource *res;
- struct pdm_dev_data *adata;
- unsigned int irqflags;
- int status;
- if (!pdev->dev.platform_data) {
dev_err(&pdev->dev, "platform_data not retrieved\n");
return -ENODEV;
- }
is this test needed?
- irqflags = *((unsigned int *)(pdev->dev.platform_data));
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
dev_err(&pdev->dev, "IORESOURCE_MEM FAILED\n");
return -ENODEV;
- }
- adata = devm_kzalloc(&pdev->dev, sizeof(*adata), GFP_KERNEL);
- if (!adata)
return -ENOMEM;
- adata->acp_base = devm_ioremap(&pdev->dev, res->start,
resource_size(res));
- if (!adata->acp_base)
return -ENOMEM;
- adata->capture_stream = NULL;
- dev_set_drvdata(&pdev->dev, adata);
- status = devm_snd_soc_register_component(&pdev->dev,
&acp_pdm_component,
&acp_pdm_dai_driver, 1);
- if (status) {
dev_err(&pdev->dev, "Fail to register acp pdm dai\n");
return -ENODEV;
return status;
- }
- return 0;
+}
+static int acp_pdm_audio_remove(struct platform_device *pdev) +{
- return 0;
+}
not needed?
+static struct platform_driver acp_pdm_dma_driver = {
- .probe = acp_pdm_audio_probe,
- .remove = acp_pdm_audio_remove,
- .driver = {
.name = "acp_rn_pdm_dma",
- },
+};
+module_platform_driver(acp_pdm_dma_driver);
[AMD Official Use Only - Internal Distribution Only]
-----Original Message----- From: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com Sent: Wednesday, May 6, 2020 3:33 AM To: Alex Deucher alexdeucher@gmail.com; alsa-devel@alsa-project.org; broonie@kernel.org; Mukunda, Vijendar Vijendar.Mukunda@amd.com; tiwai@suse.de Cc: Deucher, Alexander Alexander.Deucher@amd.com Subject: Re: [PATCH 05/14] ASoC: amd: add ACP3x PDM platform driver
+static struct snd_soc_dai_ops acp_pdm_dai_ops = {
- .hw_params = NULL,
- .trigger = NULL,
+};
doesn't seem very useful? can you remove this pdm_dai_ops?
Will remove it .
+static struct snd_soc_dai_driver acp_pdm_dai_driver = {
- .capture = {
.rates = SNDRV_PCM_RATE_48000,
.formats = SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 2,
.channels_max = 2,
.rate_min = 48000,
.rate_max = 48000,
- },
- .ops = &acp_pdm_dai_ops,
+};
+static const struct snd_soc_component_driver acp_pdm_component = {
- .name = DRV_NAME,
+};
+static int acp_pdm_audio_probe(struct platform_device *pdev) +{
- struct resource *res;
- struct pdm_dev_data *adata;
- unsigned int irqflags;
- int status;
- if (!pdev->dev.platform_data) {
dev_err(&pdev->dev, "platform_data not retrieved\n");
return -ENODEV;
- }
is this test needed?
Its only provides an extra check. This is a child device created by ACP device. ACP device passes memory and IRQ resources to this child device.
- irqflags = *((unsigned int *)(pdev->dev.platform_data));
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
dev_err(&pdev->dev, "IORESOURCE_MEM FAILED\n");
return -ENODEV;
- }
- adata = devm_kzalloc(&pdev->dev, sizeof(*adata), GFP_KERNEL);
- if (!adata)
return -ENOMEM;
- adata->acp_base = devm_ioremap(&pdev->dev, res->start,
resource_size(res));
- if (!adata->acp_base)
return -ENOMEM;
- adata->capture_stream = NULL;
- dev_set_drvdata(&pdev->dev, adata);
- status = devm_snd_soc_register_component(&pdev->dev,
&acp_pdm_component,
&acp_pdm_dai_driver, 1);
- if (status) {
dev_err(&pdev->dev, "Fail to register acp pdm dai\n");
return -ENODEV;
return status;
- }
- return 0;
+}
+static int acp_pdm_audio_remove(struct platform_device *pdev) +{
- return 0;
+}
not needed?
It gets filled in future patch.
+static struct platform_driver acp_pdm_dma_driver = {
- .probe = acp_pdm_audio_probe,
- .remove = acp_pdm_audio_remove,
- .driver = {
.name = "acp_rn_pdm_dma",
- },
+};
+module_platform_driver(acp_pdm_dma_driver);
From: Vijendar Mukunda Vijendar.Mukunda@amd.com
Whenever audio data equal to the PDM watermark level are consumed, interrupt is generated. Acknowledge the interrupt.
Signed-off-by: Vijendar Mukunda Vijendar.Mukunda@amd.com Signed-off-by: Alex Deucher alexander.deucher@amd.com --- sound/soc/amd/renoir/acp3x-pdm-dma.c | 38 ++++++++++++++++++++++++++++ sound/soc/amd/renoir/rn_acp3x.h | 2 ++ 2 files changed, 40 insertions(+)
diff --git a/sound/soc/amd/renoir/acp3x-pdm-dma.c b/sound/soc/amd/renoir/acp3x-pdm-dma.c index 680b2505d65d..4ee47a85e37e 100644 --- a/sound/soc/amd/renoir/acp3x-pdm-dma.c +++ b/sound/soc/amd/renoir/acp3x-pdm-dma.c @@ -16,6 +16,31 @@
#define DRV_NAME "acp_rn_pdm_dma"
+static irqreturn_t pdm_irq_handler(int irq, void *dev_id) +{ + struct pdm_dev_data *rn_pdm_data; + u16 cap_flag; + u32 val; + + rn_pdm_data = dev_id; + if (!rn_pdm_data) + return IRQ_NONE; + + cap_flag = 0; + val = rn_readl(rn_pdm_data->acp_base + ACP_EXTERNAL_INTR_STAT); + if ((val & BIT(PDM_DMA_STAT)) && rn_pdm_data->capture_stream) { + rn_writel(BIT(PDM_DMA_STAT), rn_pdm_data->acp_base + + ACP_EXTERNAL_INTR_STAT); + snd_pcm_period_elapsed(rn_pdm_data->capture_stream); + cap_flag = 1; + } + + if (cap_flag) + return IRQ_HANDLED; + else + return IRQ_NONE; +} + static struct snd_soc_dai_ops acp_pdm_dai_ops = { .hw_params = NULL, .trigger = NULL, @@ -66,6 +91,13 @@ static int acp_pdm_audio_probe(struct platform_device *pdev) if (!adata->acp_base) return -ENOMEM;
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res) { + dev_err(&pdev->dev, "IORESOURCE_IRQ FAILED\n"); + return -ENODEV; + } + + adata->pdm_irq = res->start; adata->capture_stream = NULL;
dev_set_drvdata(&pdev->dev, adata); @@ -77,6 +109,12 @@ static int acp_pdm_audio_probe(struct platform_device *pdev)
return -ENODEV; } + status = devm_request_irq(&pdev->dev, adata->pdm_irq, pdm_irq_handler, + irqflags, "ACP_PDM_IRQ", adata); + if (status) { + dev_err(&pdev->dev, "ACP PDM IRQ request failed\n"); + return -ENODEV; + } return 0; }
diff --git a/sound/soc/amd/renoir/rn_acp3x.h b/sound/soc/amd/renoir/rn_acp3x.h index 0b450882c6c4..1ad8a7845fda 100644 --- a/sound/soc/amd/renoir/rn_acp3x.h +++ b/sound/soc/amd/renoir/rn_acp3x.h @@ -28,8 +28,10 @@
#define ACP_ERROR_MASK 0x20000000 #define ACP_EXT_INTR_STAT_CLEAR_MASK 0xFFFFFFFF +#define PDM_DMA_STAT 0x10
struct pdm_dev_data { + u32 pdm_irq; void __iomem *acp_base; struct snd_pcm_substream *capture_stream; };
From: Vijendar Mukunda Vijendar.Mukunda@amd.com
This patch adds PDM driver DMA operations.
Signed-off-by: Vijendar Mukunda Vijendar.Mukunda@amd.com Signed-off-by: Alex Deucher alexander.deucher@amd.com --- sound/soc/amd/renoir/acp3x-pdm-dma.c | 199 +++++++++++++++++++++++++++ sound/soc/amd/renoir/rn_acp3x.h | 29 ++++ 2 files changed, 228 insertions(+)
diff --git a/sound/soc/amd/renoir/acp3x-pdm-dma.c b/sound/soc/amd/renoir/acp3x-pdm-dma.c index 4ee47a85e37e..0b5dc49f42c3 100644 --- a/sound/soc/amd/renoir/acp3x-pdm-dma.c +++ b/sound/soc/amd/renoir/acp3x-pdm-dma.c @@ -16,6 +16,25 @@
#define DRV_NAME "acp_rn_pdm_dma"
+static const struct snd_pcm_hardware acp_pdm_hardware_capture = { + .info = SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_BATCH | SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME, + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_48000, + .rate_min = 48000, + .rate_max = 48000, + .buffer_bytes_max = CAPTURE_MAX_NUM_PERIODS * CAPTURE_MAX_PERIOD_SIZE, + .period_bytes_min = CAPTURE_MIN_PERIOD_SIZE, + .period_bytes_max = CAPTURE_MAX_PERIOD_SIZE, + .periods_min = CAPTURE_MIN_NUM_PERIODS, + .periods_max = CAPTURE_MAX_NUM_PERIODS, +}; + static irqreturn_t pdm_irq_handler(int irq, void *dev_id) { struct pdm_dev_data *rn_pdm_data; @@ -41,6 +60,180 @@ static irqreturn_t pdm_irq_handler(int irq, void *dev_id) return IRQ_NONE; }
+static void init_pdm_ring_buffer(u32 physical_addr, + u32 buffer_size, + u32 watermark_size, + void __iomem *acp_base) +{ + rn_writel(physical_addr, acp_base + ACP_WOV_RX_RINGBUFADDR); + rn_writel(buffer_size, acp_base + ACP_WOV_RX_RINGBUFSIZE); + rn_writel(watermark_size, acp_base + ACP_WOV_RX_INTR_WATERMARK_SIZE); + rn_writel(0x01, acp_base + ACPAXI2AXI_ATU_CTRL); +} + +static void enable_pdm_interrupts(void __iomem *acp_base) +{ + u32 ext_int_ctrl; + + ext_int_ctrl = rn_readl(acp_base + ACP_EXTERNAL_INTR_CNTL); + ext_int_ctrl |= PDM_DMA_INTR_MASK; + rn_writel(ext_int_ctrl, acp_base + ACP_EXTERNAL_INTR_CNTL); +} + +static void disable_pdm_interrupts(void __iomem *acp_base) +{ + u32 ext_int_ctrl; + + ext_int_ctrl = rn_readl(acp_base + ACP_EXTERNAL_INTR_CNTL); + ext_int_ctrl |= ~PDM_DMA_INTR_MASK; + rn_writel(ext_int_ctrl, acp_base + ACP_EXTERNAL_INTR_CNTL); +} + +static void config_acp_dma(struct pdm_stream_instance *rtd, int direction) +{ + u16 page_idx; + u32 low, high, val; + dma_addr_t addr; + + addr = rtd->dma_addr; + val = 0; + + /* Group Enable */ + rn_writel(ACP_SRAM_PTE_OFFSET | BIT(31), rtd->acp_base + + ACPAXI2AXI_ATU_BASE_ADDR_GRP_1); + rn_writel(PAGE_SIZE_4K_ENABLE, rtd->acp_base + + ACPAXI2AXI_ATU_PAGE_SIZE_GRP_1); + + for (page_idx = 0; page_idx < rtd->num_pages; page_idx++) { + /* Load the low address of page int ACP SRAM through SRBM */ + low = lower_32_bits(addr); + high = upper_32_bits(addr); + + rn_writel(low, rtd->acp_base + ACP_SCRATCH_REG_0 + val); + high |= BIT(31); + rn_writel(high, rtd->acp_base + ACP_SCRATCH_REG_0 + val + 4); + val += 8; + addr += PAGE_SIZE; + } +} + +static int acp_pdm_dma_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime; + struct pdm_dev_data *adata; + struct pdm_stream_instance *pdm_data; + int ret; + + runtime = substream->runtime; + adata = dev_get_drvdata(component->dev); + pdm_data = kzalloc(sizeof(*pdm_data), GFP_KERNEL); + if (!pdm_data) + return -EINVAL; + + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) + runtime->hw = acp_pdm_hardware_capture; + + ret = snd_pcm_hw_constraint_integer(runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + if (ret < 0) { + dev_err(component->dev, "set integer constraint failed\n"); + kfree(pdm_data); + return ret; + } + + enable_pdm_interrupts(adata->acp_base); + + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) + adata->capture_stream = substream; + + pdm_data->acp_base = adata->acp_base; + runtime->private_data = pdm_data; + return ret; +} + +static int acp_pdm_dma_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct pdm_stream_instance *rtd; + size_t size, period_bytes; + + rtd = substream->runtime->private_data; + if (!rtd) + return -EINVAL; + size = params_buffer_bytes(params); + period_bytes = params_period_bytes(params); + rtd->dma_addr = substream->dma_buffer.addr; + rtd->num_pages = (PAGE_ALIGN(size) >> PAGE_SHIFT); + config_acp_dma(rtd, substream->stream); + init_pdm_ring_buffer(MEM_WINDOW_START, size, period_bytes, + rtd->acp_base); + return 0; +} + +static u64 acp_pdm_get_byte_count(struct pdm_stream_instance *rtd, + int direction) +{ + union acp_pdm_dma_count byte_count; + + byte_count.bcount.high = + rn_readl(rtd->acp_base + + ACP_WOV_RX_LINEARPOSITIONCNTR_HIGH); + byte_count.bcount.low = + rn_readl(rtd->acp_base + + ACP_WOV_RX_LINEARPOSITIONCNTR_LOW); + return byte_count.bytescount; +} + +static snd_pcm_uframes_t acp_pdm_dma_pointer(struct snd_soc_component *comp, + struct snd_pcm_substream *stream) +{ + struct pdm_stream_instance *rtd; + u32 pos, buffersize; + u64 bytescount; + + rtd = stream->runtime->private_data; + pos = 0; + buffersize = 0; + bytescount = 0; + + buffersize = frames_to_bytes(stream->runtime, + stream->runtime->buffer_size); + bytescount = acp_pdm_get_byte_count(rtd, stream->stream); + if (bytescount > rtd->bytescount) + bytescount -= rtd->bytescount; + pos = do_div(bytescount, buffersize); + return bytes_to_frames(stream->runtime, pos); +} + +static int acp_pdm_dma_new(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd) +{ + struct device *parent = component->dev->parent; + + snd_pcm_set_managed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV, + parent, MIN_BUFFER, MAX_BUFFER); + return 0; +} + +static int acp_pdm_dma_mmap(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct vm_area_struct *vma) +{ + return snd_pcm_lib_default_mmap(substream, vma); +} + +static int acp_pdm_dma_close(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct pdm_dev_data *adata = dev_get_drvdata(component->dev); + + disable_pdm_interrupts(adata->acp_base); + adata->capture_stream = NULL; + return 0; +} + static struct snd_soc_dai_ops acp_pdm_dai_ops = { .hw_params = NULL, .trigger = NULL, @@ -61,6 +254,12 @@ static struct snd_soc_dai_driver acp_pdm_dai_driver = {
static const struct snd_soc_component_driver acp_pdm_component = { .name = DRV_NAME, + .open = acp_pdm_dma_open, + .close = acp_pdm_dma_close, + .hw_params = acp_pdm_dma_hw_params, + .pointer = acp_pdm_dma_pointer, + .mmap = acp_pdm_dma_mmap, + .pcm_construct = acp_pdm_dma_new, };
static int acp_pdm_audio_probe(struct platform_device *pdev) diff --git a/sound/soc/amd/renoir/rn_acp3x.h b/sound/soc/amd/renoir/rn_acp3x.h index 1ad8a7845fda..3536d24374f3 100644 --- a/sound/soc/amd/renoir/rn_acp3x.h +++ b/sound/soc/amd/renoir/rn_acp3x.h @@ -29,13 +29,42 @@ #define ACP_ERROR_MASK 0x20000000 #define ACP_EXT_INTR_STAT_CLEAR_MASK 0xFFFFFFFF #define PDM_DMA_STAT 0x10 +#define PDM_DMA_INTR_MASK 0x10000 +#define ACP_ERROR_STAT 29
+#define ACP_SRAM_PTE_OFFSET 0x02050000 +#define PAGE_SIZE_4K_ENABLE 0x2 +#define MEM_WINDOW_START 0x4000000 + +#define CAPTURE_MIN_NUM_PERIODS 4 +#define CAPTURE_MAX_NUM_PERIODS 4 +#define CAPTURE_MAX_PERIOD_SIZE 8192 +#define CAPTURE_MIN_PERIOD_SIZE 4096 + +#define MAX_BUFFER (CAPTURE_MAX_PERIOD_SIZE * CAPTURE_MAX_NUM_PERIODS) +#define MIN_BUFFER MAX_BUFFER struct pdm_dev_data { u32 pdm_irq; void __iomem *acp_base; struct snd_pcm_substream *capture_stream; };
+struct pdm_stream_instance { + u16 num_pages; + u16 channels; + dma_addr_t dma_addr; + u64 bytescount; + void __iomem *acp_base; +}; + +union acp_pdm_dma_count { + struct { + u32 low; + u32 high; + } bcount; + u64 bytescount; +}; + static inline u32 rn_readl(void __iomem *base_addr) { return readl(base_addr - ACP_PHY_BASE_ADDRESS);
On 5/5/20 3:53 PM, Alex Deucher wrote:
From: Vijendar Mukunda Vijendar.Mukunda@amd.com
This patch adds PDM driver DMA operations.
Signed-off-by: Vijendar Mukunda Vijendar.Mukunda@amd.com Signed-off-by: Alex Deucher alexander.deucher@amd.com
sound/soc/amd/renoir/acp3x-pdm-dma.c | 199 +++++++++++++++++++++++++++ sound/soc/amd/renoir/rn_acp3x.h | 29 ++++ 2 files changed, 228 insertions(+)
diff --git a/sound/soc/amd/renoir/acp3x-pdm-dma.c b/sound/soc/amd/renoir/acp3x-pdm-dma.c index 4ee47a85e37e..0b5dc49f42c3 100644 --- a/sound/soc/amd/renoir/acp3x-pdm-dma.c +++ b/sound/soc/amd/renoir/acp3x-pdm-dma.c @@ -16,6 +16,25 @@
#define DRV_NAME "acp_rn_pdm_dma"
+static const struct snd_pcm_hardware acp_pdm_hardware_capture = {
- .info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_BATCH | SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME,
Can you actually resume from the same position? this seems odd when combined with INFO_BATCH which means the position is only precise at period boundaries.
- .formats = SNDRV_PCM_FMTBIT_S32_LE,
- .channels_min = 2,
- .channels_max = 2,
- .rates = SNDRV_PCM_RATE_48000,
- .rate_min = 48000,
- .rate_max = 48000,
- .buffer_bytes_max = CAPTURE_MAX_NUM_PERIODS * CAPTURE_MAX_PERIOD_SIZE,
- .period_bytes_min = CAPTURE_MIN_PERIOD_SIZE,
- .period_bytes_max = CAPTURE_MAX_PERIOD_SIZE,
- .periods_min = CAPTURE_MIN_NUM_PERIODS,
- .periods_max = CAPTURE_MAX_NUM_PERIODS,
+};
[...]
+static snd_pcm_uframes_t acp_pdm_dma_pointer(struct snd_soc_component *comp,
struct snd_pcm_substream *stream)
+{
- struct pdm_stream_instance *rtd;
- u32 pos, buffersize;
- u64 bytescount;
- rtd = stream->runtime->private_data;
- pos = 0;
- buffersize = 0;
- bytescount = 0;
these 3 inits seem unnecessary?
- buffersize = frames_to_bytes(stream->runtime,
stream->runtime->buffer_size);
- bytescount = acp_pdm_get_byte_count(rtd, stream->stream);
- if (bytescount > rtd->bytescount)
bytescount -= rtd->bytescount;
- pos = do_div(bytescount, buffersize);
- return bytes_to_frames(stream->runtime, pos);
+}
[AMD Official Use Only - Internal Distribution Only]
-----Original Message----- From: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com Sent: Wednesday, May 6, 2020 3:29 AM To: Alex Deucher alexdeucher@gmail.com; alsa-devel@alsa-project.org; broonie@kernel.org; Mukunda, Vijendar Vijendar.Mukunda@amd.com; tiwai@suse.de Cc: Deucher, Alexander Alexander.Deucher@amd.com Subject: Re: [PATCH 07/14] ASoC: amd: add acp3x pdm driver dma ops
On 5/5/20 3:53 PM, Alex Deucher wrote:
From: Vijendar Mukunda Vijendar.Mukunda@amd.com
This patch adds PDM driver DMA operations.
Signed-off-by: Vijendar Mukunda Vijendar.Mukunda@amd.com Signed-off-by: Alex Deucher alexander.deucher@amd.com
sound/soc/amd/renoir/acp3x-pdm-dma.c | 199
+++++++++++++++++++++++++++
sound/soc/amd/renoir/rn_acp3x.h | 29 ++++ 2 files changed, 228 insertions(+)
diff --git a/sound/soc/amd/renoir/acp3x-pdm-dma.c
b/sound/soc/amd/renoir/acp3x-pdm-dma.c
index 4ee47a85e37e..0b5dc49f42c3 100644 --- a/sound/soc/amd/renoir/acp3x-pdm-dma.c +++ b/sound/soc/amd/renoir/acp3x-pdm-dma.c @@ -16,6 +16,25 @@
#define DRV_NAME "acp_rn_pdm_dma"
+static const struct snd_pcm_hardware acp_pdm_hardware_capture = {
- .info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_BATCH | SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME,
Can you actually resume from the same position? this seems odd when combined with INFO_BATCH which means the position is only precise at period boundaries.
We used similar flag in Raven APU acp dma driver well. As per my understanding INFO_BATCH is more about providing period granularity when hw_ptr is queried. But PDM driver DMA pointer callback returns precise hw_ptr when queried. Correct me, if understanding is wrong.
- .formats = SNDRV_PCM_FMTBIT_S32_LE,
- .channels_min = 2,
- .channels_max = 2,
- .rates = SNDRV_PCM_RATE_48000,
- .rate_min = 48000,
- .rate_max = 48000,
- .buffer_bytes_max = CAPTURE_MAX_NUM_PERIODS *
CAPTURE_MAX_PERIOD_SIZE,
- .period_bytes_min = CAPTURE_MIN_PERIOD_SIZE,
- .period_bytes_max = CAPTURE_MAX_PERIOD_SIZE,
- .periods_min = CAPTURE_MIN_NUM_PERIODS,
- .periods_max = CAPTURE_MAX_NUM_PERIODS,
+};
[...]
+static snd_pcm_uframes_t acp_pdm_dma_pointer(struct
snd_soc_component *comp,
struct snd_pcm_substream
*stream)
+{
- struct pdm_stream_instance *rtd;
- u32 pos, buffersize;
- u64 bytescount;
- rtd = stream->runtime->private_data;
- pos = 0;
- buffersize = 0;
- bytescount = 0;
these 3 inits seem unnecessary?
Will remove it.
- buffersize = frames_to_bytes(stream->runtime,
stream->runtime->buffer_size);
- bytescount = acp_pdm_get_byte_count(rtd, stream->stream);
- if (bytescount > rtd->bytescount)
bytescount -= rtd->bytescount;
- pos = do_div(bytescount, buffersize);
- return bytes_to_frames(stream->runtime, pos);
+}
+static const struct snd_pcm_hardware acp_pdm_hardware_capture = {
- .info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_BATCH | SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME,
Can you actually resume from the same position? this seems odd when combined with INFO_BATCH which means the position is only precise at period boundaries.
We used similar flag in Raven APU acp dma driver well.
Takashi clarified during the early SOF days that if you cannot resume from the same position, then the ALSA core will attempt a prepare and restart. So if you don't support a restart from the same point, it's fine to remove this flag.
As per my understanding INFO_BATCH is more about providing period granularity when hw_ptr is queried. But PDM driver DMA pointer callback returns precise hw_ptr when queried. Correct me, if understanding is wrong.
No, INFO_BATCH means the hw_ptr is only updated with a large granularity, possibly as large as a period. if you can support precise position you should not use this flag.
From: Vijendar Mukunda Vijendar.Mukunda@amd.com
This patch adds ACP3x PDM DMA driver DAI operations.
Signed-off-by: Vijendar Mukunda Vijendar.Mukunda@amd.com Signed-off-by: Alex Deucher alexander.deucher@amd.com --- sound/soc/amd/renoir/acp3x-pdm-dma.c | 147 ++++++++++++++++++++++++++- sound/soc/amd/renoir/rn_acp3x.h | 7 ++ 2 files changed, 152 insertions(+), 2 deletions(-)
diff --git a/sound/soc/amd/renoir/acp3x-pdm-dma.c b/sound/soc/amd/renoir/acp3x-pdm-dma.c index 0b5dc49f42c3..6e8d5b85bce4 100644 --- a/sound/soc/amd/renoir/acp3x-pdm-dma.c +++ b/sound/soc/amd/renoir/acp3x-pdm-dma.c @@ -71,6 +71,27 @@ static void init_pdm_ring_buffer(u32 physical_addr, rn_writel(0x01, acp_base + ACPAXI2AXI_ATU_CTRL); }
+static void config_pdm_stream_params(unsigned int ch_mask, + void __iomem *acp_base) +{ + rn_writel(ch_mask, acp_base + ACP_WOV_PDM_NO_OF_CHANNELS); + rn_writel(PDM_DECIMATION_FACTOR, acp_base + + ACP_WOV_PDM_DECIMATION_FACTOR); +} + +static void enable_pdm_clock(void __iomem *acp_base) +{ + u32 pdm_clk_enable, pdm_ctrl; + + pdm_clk_enable = ACP_PDM_CLK_FREQ_MASK; + pdm_ctrl = 0x00; + + rn_writel(pdm_clk_enable, acp_base + ACP_WOV_CLK_CTRL); + pdm_ctrl = rn_readl(acp_base + ACP_WOV_MISC_CTRL); + pdm_ctrl |= ACP_WOV_MISC_CTRL_MASK; + rn_writel(pdm_ctrl, acp_base + ACP_WOV_MISC_CTRL); +} + static void enable_pdm_interrupts(void __iomem *acp_base) { u32 ext_int_ctrl; @@ -89,6 +110,77 @@ static void disable_pdm_interrupts(void __iomem *acp_base) rn_writel(ext_int_ctrl, acp_base + ACP_EXTERNAL_INTR_CNTL); }
+static bool check_pdm_dma_status(void __iomem *acp_base) +{ + bool pdm_dma_status; + u32 pdm_enable, pdm_dma_enable; + + pdm_dma_status = false; + pdm_enable = rn_readl(acp_base + ACP_WOV_PDM_ENABLE); + pdm_dma_enable = rn_readl(acp_base + ACP_WOV_PDM_DMA_ENABLE); + if ((pdm_enable & ACP_PDM_ENABLE) && (pdm_dma_enable & + ACP_PDM_DMA_EN_STATUS)) + pdm_dma_status = true; + return pdm_dma_status; +} + +static int start_pdm_dma(void __iomem *acp_base) +{ + u32 pdm_enable; + u32 pdm_dma_enable; + int timeout; + + pdm_enable = 0x01; + pdm_dma_enable = 0x01; + + enable_pdm_clock(acp_base); + rn_writel(pdm_enable, acp_base + ACP_WOV_PDM_ENABLE); + rn_writel(pdm_dma_enable, acp_base + ACP_WOV_PDM_DMA_ENABLE); + pdm_dma_enable = 0x00; + timeout = 0; + while (++timeout < 20000) { + pdm_dma_enable = rn_readl(acp_base + ACP_WOV_PDM_DMA_ENABLE); + if ((pdm_dma_enable & 0x02) == ACP_PDM_DMA_EN_STATUS) + return 0; + udelay(5); + } + return -ETIMEDOUT; +} + +static int stop_pdm_dma(void __iomem *acp_base) +{ + u32 pdm_enable, pdm_dma_enable, pdm_fifo_flush; + int timeout; + + pdm_enable = 0x00; + pdm_dma_enable = 0x00; + pdm_fifo_flush = 0x00; + + pdm_enable = rn_readl(acp_base + ACP_WOV_PDM_ENABLE); + pdm_dma_enable = rn_readl(acp_base + ACP_WOV_PDM_DMA_ENABLE); + if (pdm_dma_enable & 0x01) { + pdm_dma_enable = 0x02; + rn_writel(pdm_dma_enable, acp_base + ACP_WOV_PDM_DMA_ENABLE); + pdm_dma_enable = 0x00; + timeout = 0; + while (++timeout < 20000) { + pdm_dma_enable = rn_readl(acp_base + + ACP_WOV_PDM_DMA_ENABLE); + if ((pdm_dma_enable & 0x02) == 0x00) + return 0; + udelay(5); + } + if (timeout == 20000) + return -ETIMEDOUT; + } + if (pdm_enable == ACP_PDM_ENABLE) { + pdm_enable = ACP_PDM_DISABLE; + rn_writel(pdm_enable, acp_base + ACP_WOV_PDM_ENABLE); + } + rn_writel(0x01, acp_base + ACP_WOV_PDM_FIFO_FLUSH); + return 0; +} + static void config_acp_dma(struct pdm_stream_instance *rtd, int direction) { u16 page_idx; @@ -234,9 +326,60 @@ static int acp_pdm_dma_close(struct snd_soc_component *component, return 0; }
+static int acp_pdm_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct pdm_stream_instance *rtd; + unsigned int ch_mask; + + rtd = substream->runtime->private_data; + switch (params_channels(params)) { + case TWO_CH: + default: + ch_mask = 0x00; + break; + } + config_pdm_stream_params(ch_mask, rtd->acp_base); + return 0; +} + +static int acp_pdm_dai_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *dai) +{ + struct pdm_stream_instance *rtd; + int ret; + bool pdm_status; + + rtd = substream->runtime->private_data; + ret = 0; + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + rtd->bytescount = acp_pdm_get_byte_count(rtd, + substream->stream); + pdm_status = check_pdm_dma_status(rtd->acp_base); + if (!pdm_status) + ret = start_pdm_dma(rtd->acp_base); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + pdm_status = check_pdm_dma_status(rtd->acp_base); + if (pdm_status) + ret = stop_pdm_dma(rtd->acp_base); + break; + default: + ret = -EINVAL; + break; + } + return ret; +} + static struct snd_soc_dai_ops acp_pdm_dai_ops = { - .hw_params = NULL, - .trigger = NULL, + .hw_params = acp_pdm_dai_hw_params, + .trigger = acp_pdm_dai_trigger, };
static struct snd_soc_dai_driver acp_pdm_dai_driver = { diff --git a/sound/soc/amd/renoir/rn_acp3x.h b/sound/soc/amd/renoir/rn_acp3x.h index 3536d24374f3..f63e232565af 100644 --- a/sound/soc/amd/renoir/rn_acp3x.h +++ b/sound/soc/amd/renoir/rn_acp3x.h @@ -31,6 +31,13 @@ #define PDM_DMA_STAT 0x10 #define PDM_DMA_INTR_MASK 0x10000 #define ACP_ERROR_STAT 29 +#define PDM_DECIMATION_FACTOR 0x2 +#define ACP_PDM_CLK_FREQ_MASK 0x07 +#define ACP_WOV_MISC_CTRL_MASK 0x10 +#define ACP_PDM_ENABLE 0x01 +#define ACP_PDM_DISABLE 0x00 +#define ACP_PDM_DMA_EN_STATUS 0x02 +#define TWO_CH 0x02
#define ACP_SRAM_PTE_OFFSET 0x02050000 #define PAGE_SIZE_4K_ENABLE 0x2
+static int start_pdm_dma(void __iomem *acp_base) +{
- u32 pdm_enable;
- u32 pdm_dma_enable;
- int timeout;
- pdm_enable = 0x01;
- pdm_dma_enable = 0x01;
- enable_pdm_clock(acp_base);
- rn_writel(pdm_enable, acp_base + ACP_WOV_PDM_ENABLE);
- rn_writel(pdm_dma_enable, acp_base + ACP_WOV_PDM_DMA_ENABLE);
- pdm_dma_enable = 0x00;
- timeout = 0;
- while (++timeout < 20000) {
pdm_dma_enable = rn_readl(acp_base + ACP_WOV_PDM_DMA_ENABLE);
if ((pdm_dma_enable & 0x02) == ACP_PDM_DMA_EN_STATUS)
return 0;
udelay(5);
- }
maybe use human-readable defines for timeout and delay? e.g.
#define TIMEOUT_MS 100 #define DELAY_US 5
- return -ETIMEDOUT;
+}
+static int stop_pdm_dma(void __iomem *acp_base) +{
- u32 pdm_enable, pdm_dma_enable, pdm_fifo_flush;
- int timeout;
- pdm_enable = 0x00;
- pdm_dma_enable = 0x00;
- pdm_fifo_flush = 0x00;
- pdm_enable = rn_readl(acp_base + ACP_WOV_PDM_ENABLE);
- pdm_dma_enable = rn_readl(acp_base + ACP_WOV_PDM_DMA_ENABLE);
- if (pdm_dma_enable & 0x01) {
pdm_dma_enable = 0x02;
rn_writel(pdm_dma_enable, acp_base + ACP_WOV_PDM_DMA_ENABLE);
pdm_dma_enable = 0x00;
timeout = 0;
while (++timeout < 20000) {
pdm_dma_enable = rn_readl(acp_base +
ACP_WOV_PDM_DMA_ENABLE);
if ((pdm_dma_enable & 0x02) == 0x00)
return 0;
udelay(5);
}
if (timeout == 20000)
if this test needed, it'll be always true, no?
return -ETIMEDOUT;
- }
- if (pdm_enable == ACP_PDM_ENABLE) {
pdm_enable = ACP_PDM_DISABLE;
rn_writel(pdm_enable, acp_base + ACP_WOV_PDM_ENABLE);
- }
- rn_writel(0x01, acp_base + ACP_WOV_PDM_FIFO_FLUSH);
- return 0;
+}
+static int acp_pdm_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
+{
- struct pdm_stream_instance *rtd;
- unsigned int ch_mask;
- rtd = substream->runtime->private_data;
- switch (params_channels(params)) {
- case TWO_CH:
- default:
ch_mask = 0x00;
break;
- }
the switch doesn't appear very useful at the moment?
- config_pdm_stream_params(ch_mask, rtd->acp_base);
- return 0;
+}
-----Original Message----- From: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com Sent: Wednesday, May 6, 2020 3:25 AM To: Alex Deucher alexdeucher@gmail.com; alsa-devel@alsa-project.org; broonie@kernel.org; Mukunda, Vijendar Vijendar.Mukunda@amd.com; tiwai@suse.de Cc: Deucher, Alexander Alexander.Deucher@amd.com Subject: Re: [PATCH 08/14] ASoC: amd: add ACP PDM DMA driver dai ops
+static int start_pdm_dma(void __iomem *acp_base) +{
- u32 pdm_enable;
- u32 pdm_dma_enable;
- int timeout;
- pdm_enable = 0x01;
- pdm_dma_enable = 0x01;
- enable_pdm_clock(acp_base);
- rn_writel(pdm_enable, acp_base + ACP_WOV_PDM_ENABLE);
- rn_writel(pdm_dma_enable, acp_base +
ACP_WOV_PDM_DMA_ENABLE);
- pdm_dma_enable = 0x00;
- timeout = 0;
- while (++timeout < 20000) {
pdm_dma_enable = rn_readl(acp_base +
ACP_WOV_PDM_DMA_ENABLE);
if ((pdm_dma_enable & 0x02) ==
ACP_PDM_DMA_EN_STATUS)
return 0;
udelay(5);
- }
maybe use human-readable defines for timeout and delay? e.g.
#define TIMEOUT_MS 100 #define DELAY_US 5
Will fix it.
- return -ETIMEDOUT;
+}
+static int stop_pdm_dma(void __iomem *acp_base) +{
- u32 pdm_enable, pdm_dma_enable, pdm_fifo_flush;
- int timeout;
- pdm_enable = 0x00;
- pdm_dma_enable = 0x00;
- pdm_fifo_flush = 0x00;
- pdm_enable = rn_readl(acp_base + ACP_WOV_PDM_ENABLE);
- pdm_dma_enable = rn_readl(acp_base +
ACP_WOV_PDM_DMA_ENABLE);
- if (pdm_dma_enable & 0x01) {
pdm_dma_enable = 0x02;
rn_writel(pdm_dma_enable, acp_base +
ACP_WOV_PDM_DMA_ENABLE);
pdm_dma_enable = 0x00;
timeout = 0;
while (++timeout < 20000) {
pdm_dma_enable = rn_readl(acp_base +
ACP_WOV_PDM_DMA_ENABLE);
if ((pdm_dma_enable & 0x02) == 0x00)
return 0;
udelay(5);
}
if (timeout == 20000)
if this test needed, it'll be always true, no?
Sorry its my bad. It shouldn't return 0 when ACP DMA transfer is stopped. It should break the while loop then it should continue to do register programming for stopping the PDM decoder and flushing the FIFO.. timeout check only to verify whether is there any timeout occurred for stopping the PDM DMA transfer or not.
Will modify the logic and share the updated patch.
return -ETIMEDOUT;
- }
- if (pdm_enable == ACP_PDM_ENABLE) {
pdm_enable = ACP_PDM_DISABLE;
rn_writel(pdm_enable, acp_base + ACP_WOV_PDM_ENABLE);
- }
- rn_writel(0x01, acp_base + ACP_WOV_PDM_FIFO_FLUSH);
- return 0;
+}
+static int acp_pdm_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
+{
- struct pdm_stream_instance *rtd;
- unsigned int ch_mask;
- rtd = substream->runtime->private_data;
- switch (params_channels(params)) {
- case TWO_CH:
- default:
ch_mask = 0x00;
break;
- }
the switch doesn't appear very useful at the moment?
We kept it for future reference to extend support for more than 2 channels.
- config_pdm_stream_params(ch_mask, rtd->acp_base);
- return 0;
+}
From: Vijendar Mukunda Vijendar.Mukunda@amd.com
Add Renoir ACP Pci driver pm ops.
Signed-off-by: Vijendar Mukunda Vijendar.Mukunda@amd.com Signed-off-by: Alex Deucher alexander.deucher@amd.com --- sound/soc/amd/renoir/rn-pci-acp3x.c | 48 +++++++++++++++++++++++++++++ sound/soc/amd/renoir/rn_acp3x.h | 2 ++ 2 files changed, 50 insertions(+)
diff --git a/sound/soc/amd/renoir/rn-pci-acp3x.c b/sound/soc/amd/renoir/rn-pci-acp3x.c index 362409ef0d85..6d013a1bffa6 100644 --- a/sound/soc/amd/renoir/rn-pci-acp3x.c +++ b/sound/soc/amd/renoir/rn-pci-acp3x.c @@ -10,6 +10,7 @@ #include <linux/delay.h> #include <linux/platform_device.h> #include <linux/interrupt.h> +#include <linux/pm_runtime.h>
#include "rn_acp3x.h"
@@ -233,6 +234,12 @@ static int snd_rn_acp_probe(struct pci_dev *pci, ret = PTR_ERR(adata->pdev); goto unregister_devs; } + pm_runtime_set_autosuspend_delay(&pci->dev, ACP_SUSPEND_DELAY_MS); + pm_runtime_use_autosuspend(&pci->dev); + pm_runtime_set_active(&pci->dev); + pm_runtime_put_noidle(&pci->dev); + pm_runtime_enable(&pci->dev); + pm_runtime_allow(&pci->dev); return 0;
unregister_devs: @@ -250,6 +257,42 @@ static int snd_rn_acp_probe(struct pci_dev *pci, return ret; }
+static int snd_rn_acp_suspend(struct device *dev) +{ + int ret; + struct acp_dev_data *adata; + + adata = dev_get_drvdata(dev); + ret = rn_acp_deinit(adata->acp_base); + if (ret) + dev_err(dev, "ACP de-init failed\n"); + else + dev_dbg(dev, "ACP de-initialized\n"); + + return 0; +} + +static int snd_rn_acp_resume(struct device *dev) +{ + int ret; + struct acp_dev_data *adata; + + adata = dev_get_drvdata(dev); + ret = rn_acp_init(adata->acp_base); + if (ret) { + dev_err(dev, "ACP init failed\n"); + return ret; + } + return 0; +} + +static const struct dev_pm_ops rn_acp_pm = { + .runtime_suspend = snd_rn_acp_suspend, + .runtime_resume = snd_rn_acp_resume, + .suspend = snd_rn_acp_suspend, + .resume = snd_rn_acp_resume, +}; + static void snd_rn_acp_remove(struct pci_dev *pci) { struct acp_dev_data *adata; @@ -260,6 +303,8 @@ static void snd_rn_acp_remove(struct pci_dev *pci) ret = rn_acp_deinit(adata->acp_base); if (ret) dev_err(&pci->dev, "ACP de-init failed\n"); + pm_runtime_disable(&pci->dev); + pm_runtime_get_noresume(&pci->dev); pci_disable_msi(pci); pci_release_regions(pci); pci_disable_device(pci); @@ -278,6 +323,9 @@ static struct pci_driver rn_acp_driver = { .id_table = snd_rn_acp_ids, .probe = snd_rn_acp_probe, .remove = snd_rn_acp_remove, + .driver = { + .pm = &rn_acp_pm, + } };
module_pci_driver(rn_acp_driver); diff --git a/sound/soc/amd/renoir/rn_acp3x.h b/sound/soc/amd/renoir/rn_acp3x.h index f63e232565af..f24a4da8c721 100644 --- a/sound/soc/amd/renoir/rn_acp3x.h +++ b/sound/soc/amd/renoir/rn_acp3x.h @@ -38,6 +38,8 @@ #define ACP_PDM_DISABLE 0x00 #define ACP_PDM_DMA_EN_STATUS 0x02 #define TWO_CH 0x02 +/* time in ms for runtime suspend delay */ +#define ACP_SUSPEND_DELAY_MS 2000
#define ACP_SRAM_PTE_OFFSET 0x02050000 #define PAGE_SIZE_4K_ENABLE 0x2
diff --git a/sound/soc/amd/renoir/rn-pci-acp3x.c b/sound/soc/amd/renoir/rn-pci-acp3x.c index 362409ef0d85..6d013a1bffa6 100644 --- a/sound/soc/amd/renoir/rn-pci-acp3x.c +++ b/sound/soc/amd/renoir/rn-pci-acp3x.c @@ -10,6 +10,7 @@ #include <linux/delay.h> #include <linux/platform_device.h> #include <linux/interrupt.h> +#include <linux/pm_runtime.h>
#include "rn_acp3x.h"
@@ -233,6 +234,12 @@ static int snd_rn_acp_probe(struct pci_dev *pci, ret = PTR_ERR(adata->pdev); goto unregister_devs; }
- pm_runtime_set_autosuspend_delay(&pci->dev, ACP_SUSPEND_DELAY_MS);
- pm_runtime_use_autosuspend(&pci->dev);
- pm_runtime_set_active(&pci->dev);
is the set_active() needed? I haven't seen this in the other PCI audio drivers?
- pm_runtime_put_noidle(&pci->dev);
- pm_runtime_enable(&pci->dev);
same, is the _enable() needed()?
pm_runtime_allow(&pci->dev); return 0;
unregister_devs:
@@ -250,6 +257,42 @@ static int snd_rn_acp_probe(struct pci_dev *pci, return ret; }
-----Original Message----- From: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com Sent: Wednesday, May 6, 2020 3:19 AM To: Alex Deucher alexdeucher@gmail.com; alsa-devel@alsa-project.org; broonie@kernel.org; Mukunda, Vijendar Vijendar.Mukunda@amd.com; tiwai@suse.de Cc: Deucher, Alexander Alexander.Deucher@amd.com Subject: Re: [PATCH 09/14] ASoC: amd: add Renoir ACP PCI driver PM ops
diff --git a/sound/soc/amd/renoir/rn-pci-acp3x.c
b/sound/soc/amd/renoir/rn-pci-acp3x.c
index 362409ef0d85..6d013a1bffa6 100644 --- a/sound/soc/amd/renoir/rn-pci-acp3x.c +++ b/sound/soc/amd/renoir/rn-pci-acp3x.c @@ -10,6 +10,7 @@ #include <linux/delay.h> #include <linux/platform_device.h> #include <linux/interrupt.h> +#include <linux/pm_runtime.h>
#include "rn_acp3x.h"
@@ -233,6 +234,12 @@ static int snd_rn_acp_probe(struct pci_dev *pci, ret = PTR_ERR(adata->pdev); goto unregister_devs; }
- pm_runtime_set_autosuspend_delay(&pci->dev,
ACP_SUSPEND_DELAY_MS);
- pm_runtime_use_autosuspend(&pci->dev);
- pm_runtime_set_active(&pci->dev);
is the set_active() needed? I haven't seen this in the other PCI audio drivers?
We have similar implementation in our Raven ACP PCI driver as well which got up streamed. I will give a try by modifying this sequence. Could you please point me , what's exactly wrong with this code?
- pm_runtime_put_noidle(&pci->dev);
- pm_runtime_enable(&pci->dev);
same, is the _enable() needed()?
We have similar implementation in Raven ACP PCI driver as well.
pm_runtime_allow(&pci->dev); return 0;
unregister_devs:
@@ -250,6 +257,42 @@ static int snd_rn_acp_probe(struct pci_dev *pci, return ret; }
@@ -233,6 +234,12 @@ static int snd_rn_acp_probe(struct pci_dev *pci, ret = PTR_ERR(adata->pdev); goto unregister_devs; }
- pm_runtime_set_autosuspend_delay(&pci->dev,
ACP_SUSPEND_DELAY_MS);
- pm_runtime_use_autosuspend(&pci->dev);
- pm_runtime_set_active(&pci->dev);
is the set_active() needed? I haven't seen this in the other PCI audio drivers? >
We have similar implementation in our Raven ACP PCI driver as well which got up streamed. I will give a try by modifying this sequence. Could you please point me , what's exactly wrong with this code?
you would use pm_runtime_set_active() if the device was suspended. I don't think this can possibly happen since there is a _get done by the PCI core, which you compensate for in the line below.
Also look at drivers/pci/pci.c, the core already does this set_active() and _enable().
void pci_pm_init(struct pci_dev *dev) { ...
pm_runtime_forbid(&dev->dev); pm_runtime_set_active(&dev->dev); pm_runtime_enable(&dev->dev);
- pm_runtime_put_noidle(&pci->dev);
- pm_runtime_enable(&pci->dev);
same, is the _enable() needed()?
We have similar implementation in Raven ACP PCI driver as well.
It's quite common unfortunately that extended pm_runtime sequences are used without checking what's necessary - it took Intel some time to clearly define what we needed and what was redundant/noop.
pm_runtime_allow(&pci->dev); return 0;
unregister_devs:
@@ -250,6 +257,42 @@ static int snd_rn_acp_probe(struct pci_dev *pci, return ret; }
From: Vijendar Mukunda Vijendar.Mukunda@amd.com
Add ACP PDM DMA driver pm ops.
Signed-off-by: Vijendar Mukunda Vijendar.Mukunda@amd.com Signed-off-by: Alex Deucher alexander.deucher@amd.com --- sound/soc/amd/renoir/acp3x-pdm-dma.c | 53 ++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+)
diff --git a/sound/soc/amd/renoir/acp3x-pdm-dma.c b/sound/soc/amd/renoir/acp3x-pdm-dma.c index 6e8d5b85bce4..ef256c777873 100644 --- a/sound/soc/amd/renoir/acp3x-pdm-dma.c +++ b/sound/soc/amd/renoir/acp3x-pdm-dma.c @@ -8,6 +8,7 @@ #include <linux/module.h> #include <linux/err.h> #include <linux/io.h> +#include <linux/pm_runtime.h> #include <sound/pcm_params.h> #include <sound/soc.h> #include <sound/soc-dai.h> @@ -457,19 +458,71 @@ static int acp_pdm_audio_probe(struct platform_device *pdev) dev_err(&pdev->dev, "ACP PDM IRQ request failed\n"); return -ENODEV; } + pm_runtime_set_autosuspend_delay(&pdev->dev, ACP_SUSPEND_DELAY_MS); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_enable(&pdev->dev); + pm_runtime_allow(&pdev->dev); return 0; }
static int acp_pdm_audio_remove(struct platform_device *pdev) { + pm_runtime_disable(&pdev->dev); return 0; }
+static int acp_pdm_resume(struct device *dev) +{ + struct pdm_dev_data *adata; + struct snd_pcm_runtime *runtime; + struct pdm_stream_instance *rtd; + u32 period_bytes, buffer_len; + + adata = dev_get_drvdata(dev); + if (adata->capture_stream && adata->capture_stream->runtime) { + runtime = adata->capture_stream->runtime; + rtd = runtime->private_data; + period_bytes = frames_to_bytes(runtime, runtime->period_size); + buffer_len = frames_to_bytes(runtime, runtime->buffer_size); + config_acp_dma(rtd, SNDRV_PCM_STREAM_CAPTURE); + init_pdm_ring_buffer(MEM_WINDOW_START, buffer_len, period_bytes, + adata->acp_base); + } + enable_pdm_interrupts(adata->acp_base); + return 0; +} + +static int acp_pdm_runtime_suspend(struct device *dev) +{ + struct pdm_dev_data *adata; + + adata = dev_get_drvdata(dev); + disable_pdm_interrupts(adata->acp_base); + + return 0; +} + +static int acp_pdm_runtime_resume(struct device *dev) +{ + struct pdm_dev_data *adata; + + adata = dev_get_drvdata(dev); + enable_pdm_interrupts(adata->acp_base); + return 0; +} + +static const struct dev_pm_ops acp_pdm_pm_ops = { + .runtime_suspend = acp_pdm_runtime_suspend, + .runtime_resume = acp_pdm_runtime_resume, + .resume = acp_pdm_resume, +}; + static struct platform_driver acp_pdm_dma_driver = { .probe = acp_pdm_audio_probe, .remove = acp_pdm_audio_remove, .driver = { .name = "acp_rn_pdm_dma", + .pm = &acp_pdm_pm_ops, }, };
From: Vijendar Mukunda Vijendar.Mukunda@amd.com
Renoir ACP3x drivers can be built by selecting necessary kernel config option. The patch enables build support of the same.
Signed-off-by: Vijendar Mukunda Vijendar.Mukunda@amd.com Signed-off-by: Alex Deucher alexander.deucher@amd.com --- sound/soc/amd/Kconfig | 6 ++++++ sound/soc/amd/Makefile | 1 + sound/soc/amd/renoir/Makefile | 6 ++++++ 3 files changed, 13 insertions(+) create mode 100644 sound/soc/amd/renoir/Makefile
diff --git a/sound/soc/amd/Kconfig b/sound/soc/amd/Kconfig index bce4cee5cb54..5f57a47382b4 100644 --- a/sound/soc/amd/Kconfig +++ b/sound/soc/amd/Kconfig @@ -36,3 +36,9 @@ config SND_SOC_AMD_RV_RT5682_MACH depends on SND_SOC_AMD_ACP3x && I2C && CROS_EC help This option enables machine driver for RT5682 and MAX9835. + +config SND_SOC_AMD_RENOIR + tristate "AMD Audio Coprocessor - Renoir support" + depends on X86 && PCI + help + This option enables ACP support for Renoir platform diff --git a/sound/soc/amd/Makefile b/sound/soc/amd/Makefile index e6f3d9b469f3..e6df2f72a2a1 100644 --- a/sound/soc/amd/Makefile +++ b/sound/soc/amd/Makefile @@ -9,3 +9,4 @@ obj-$(CONFIG_SND_SOC_AMD_CZ_DA7219MX98357_MACH) += snd-soc-acp-da7219mx98357-mac obj-$(CONFIG_SND_SOC_AMD_CZ_RT5645_MACH) += snd-soc-acp-rt5645-mach.o obj-$(CONFIG_SND_SOC_AMD_ACP3x) += raven/ obj-$(CONFIG_SND_SOC_AMD_RV_RT5682_MACH) += snd-soc-acp-rt5682-mach.o +obj-$(CONFIG_SND_SOC_AMD_RENOIR) += renoir/ diff --git a/sound/soc/amd/renoir/Makefile b/sound/soc/amd/renoir/Makefile new file mode 100644 index 000000000000..43100515c7db --- /dev/null +++ b/sound/soc/amd/renoir/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Renoir platform Support +snd-rn-pci-acp3x-objs := rn-pci-acp3x.o +snd-acp3x-pdm-dma-objs := acp3x-pdm-dma.o +obj-$(CONFIG_SND_SOC_AMD_RENOIR) += snd-rn-pci-acp3x.o +obj-$(CONFIG_SND_SOC_AMD_RENOIR) += snd-acp3x-pdm-dma.o
From: Vijendar Mukunda Vijendar.Mukunda@amd.com
Create platform devices for generic dmic codec driver and machine driver. These platform devices required for creation of sound card.
Signed-off-by: Vijendar Mukunda Vijendar.Mukunda@amd.com Signed-off-by: Alex Deucher alexander.deucher@amd.com --- sound/soc/amd/renoir/rn-pci-acp3x.c | 51 ++++++++++++++++++----------- sound/soc/amd/renoir/rn_acp3x.h | 1 + 2 files changed, 32 insertions(+), 20 deletions(-)
diff --git a/sound/soc/amd/renoir/rn-pci-acp3x.c b/sound/soc/amd/renoir/rn-pci-acp3x.c index 6d013a1bffa6..04dc6237a4b3 100644 --- a/sound/soc/amd/renoir/rn-pci-acp3x.c +++ b/sound/soc/amd/renoir/rn-pci-acp3x.c @@ -21,7 +21,7 @@ MODULE_PARM_DESC(acp_power_gating, "Enable acp power gating"); struct acp_dev_data { void __iomem *acp_base; struct resource *res; - struct platform_device *pdev; + struct platform_device *pdev[ACP_DEVS]; };
static int rn_acp_power_on(void __iomem *acp_base) @@ -156,9 +156,9 @@ static int snd_rn_acp_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { struct acp_dev_data *adata; - struct platform_device_info pdevinfo; + struct platform_device_info pdevinfo[ACP_DEVS]; unsigned int irqflags; - int ret; + int ret, index; u32 addr;
if (pci_enable_device(pci)) { @@ -219,20 +219,29 @@ static int snd_rn_acp_probe(struct pci_dev *pci, adata->res[1].end = pci->irq;
memset(&pdevinfo, 0, sizeof(pdevinfo)); - pdevinfo.name = "acp_rn_pdm_dma"; - pdevinfo.id = 0; - pdevinfo.parent = &pci->dev; - pdevinfo.num_res = 2; - pdevinfo.res = adata->res; - pdevinfo.data = &irqflags; - pdevinfo.size_data = sizeof(irqflags); - - adata->pdev = platform_device_register_full(&pdevinfo); - if (IS_ERR(adata->pdev)) { - dev_err(&pci->dev, "cannot register %s device\n", - pdevinfo.name); - ret = PTR_ERR(adata->pdev); - goto unregister_devs; + pdevinfo[0].name = "acp_rn_pdm_dma"; + pdevinfo[0].id = 0; + pdevinfo[0].parent = &pci->dev; + pdevinfo[0].num_res = 2; + pdevinfo[0].res = adata->res; + pdevinfo[0].data = &irqflags; + pdevinfo[0].size_data = sizeof(irqflags); + + pdevinfo[1].name = "dmic-codec"; + pdevinfo[1].id = 0; + pdevinfo[1].parent = &pci->dev; + pdevinfo[2].name = "acp_pdm_mach"; + pdevinfo[2].id = 0; + pdevinfo[2].parent = &pci->dev; + for (index = 0; index < ACP_DEVS; index++) { + adata->pdev[index] = + platform_device_register_full(&pdevinfo[index]); + if (IS_ERR(adata->pdev[index])) { + dev_err(&pci->dev, "cannot register %s device\n", + pdevinfo[index].name); + ret = PTR_ERR(adata->pdev[index]); + goto unregister_devs; + } } pm_runtime_set_autosuspend_delay(&pci->dev, ACP_SUSPEND_DELAY_MS); pm_runtime_use_autosuspend(&pci->dev); @@ -243,7 +252,8 @@ static int snd_rn_acp_probe(struct pci_dev *pci, return 0;
unregister_devs: - platform_device_unregister(adata->pdev); + for (index = 0; index < ACP_DEVS; index++) + platform_device_unregister(adata->pdev[index]); de_init: if (rn_acp_deinit(adata->acp_base)) dev_err(&pci->dev, "ACP de-init failed\n"); @@ -296,10 +306,11 @@ static const struct dev_pm_ops rn_acp_pm = { static void snd_rn_acp_remove(struct pci_dev *pci) { struct acp_dev_data *adata; - int ret; + int ret, index;
adata = pci_get_drvdata(pci); - platform_device_unregister(adata->pdev); + for (index = 0; index < ACP_DEVS; index++) + platform_device_unregister(adata->pdev[index]); ret = rn_acp_deinit(adata->acp_base); if (ret) dev_err(&pci->dev, "ACP de-init failed\n"); diff --git a/sound/soc/amd/renoir/rn_acp3x.h b/sound/soc/amd/renoir/rn_acp3x.h index f24a4da8c721..ed1a4d27eea7 100644 --- a/sound/soc/amd/renoir/rn_acp3x.h +++ b/sound/soc/amd/renoir/rn_acp3x.h @@ -7,6 +7,7 @@
#include "rn_chip_offset_byte.h"
+#define ACP_DEVS 3 #define ACP_PHY_BASE_ADDRESS 0x1240000 #define ACP_REG_START 0x1240000 #define ACP_REG_END 0x1250200
From: Vijendar Mukunda Vijendar.Mukunda@amd.com
This patch adds Renoir Machine driver for dmic support.
Signed-off-by: Vijendar Mukunda Vijendar.Mukunda@amd.com Signed-off-by: Alex Deucher alexander.deucher@amd.com --- sound/soc/amd/renoir/acp3x-rn.c | 112 ++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 sound/soc/amd/renoir/acp3x-rn.c
diff --git a/sound/soc/amd/renoir/acp3x-rn.c b/sound/soc/amd/renoir/acp3x-rn.c new file mode 100644 index 000000000000..8556446637dc --- /dev/null +++ b/sound/soc/amd/renoir/acp3x-rn.c @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// Machine driver for AMD Renoir platform using DMIC +// +//Copyright 2020 Advanced Micro Devices, Inc. + +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <linux/module.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <linux/io.h> + +#include "rn_acp3x.h" + +#define DRV_NAME "acp_pdm_mach" + +static int acp_pdm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + return 0; +} + +static struct snd_soc_ops acp_pdm_ops = { + .hw_params = acp_pdm_hw_params, +}; + +static int acp_init(struct snd_soc_pcm_runtime *rtd) +{ + return 0; +} + +SND_SOC_DAILINK_DEF(acp_pdm, + DAILINK_COMP_ARRAY(COMP_CPU("acp_rn_pdm_dma.0"))); + +SND_SOC_DAILINK_DEF(dmic_codec, + DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec.0", + "dmic-hifi"))); + +SND_SOC_DAILINK_DEF(platform, + DAILINK_COMP_ARRAY(COMP_PLATFORM("acp_rn_pdm_dma.0"))); + +static struct snd_soc_dai_link acp_dai_pdm[] = { + { + .name = "acp3x-dmic-capture", + .stream_name = "DMIC capture", + .ops = &acp_pdm_ops, + .init = acp_init, + .capture_only = 1, + SND_SOC_DAILINK_REG(acp_pdm, dmic_codec, platform), + }, +}; + +static struct snd_soc_card acp_card = { + .name = "acp", + .owner = THIS_MODULE, + .dai_link = acp_dai_pdm, + .num_links = 1, +}; + +static int acp_probe(struct platform_device *pdev) +{ + int ret; + struct acp_pdm *machine = NULL; + struct snd_soc_card *card; + + card = &acp_card; + acp_card.dev = &pdev->dev; + + platform_set_drvdata(pdev, card); + snd_soc_card_set_drvdata(card, machine); + ret = devm_snd_soc_register_card(&pdev->dev, card); + if (ret) { + dev_err(&pdev->dev, + "snd_soc_register_card(%s) failed: %d\n", + acp_card.name, ret); + return ret; + } + if (ret) { + dev_err(&pdev->dev, + "snd_soc_register_card(%s) failed: %d\n", + acp_card.name, ret); + return ret; + } + return 0; +} + +static struct platform_driver acp_mach_driver = { + .driver = { + .name = "acp_pdm_mach", + .pm = &snd_soc_pm_ops, + }, + .probe = acp_probe, +}; + +static int __init acp_audio_init(void) +{ + platform_driver_register(&acp_mach_driver); + return 0; +} + +static void __exit acp_audio_exit(void) +{ + platform_driver_unregister(&acp_mach_driver); +} + +module_init(acp_audio_init); +module_exit(acp_audio_exit); + +MODULE_AUTHOR("Vijendar.Mukunda@amd.com"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRV_NAME);
+static int acp_probe(struct platform_device *pdev) +{
- int ret;
- struct acp_pdm *machine = NULL;
- struct snd_soc_card *card;
- card = &acp_card;
- acp_card.dev = &pdev->dev;
- platform_set_drvdata(pdev, card);
- snd_soc_card_set_drvdata(card, machine);
- ret = devm_snd_soc_register_card(&pdev->dev, card);
- if (ret) {
dev_err(&pdev->dev,
"snd_soc_register_card(%s) failed: %d\n",
acp_card.name, ret);
return ret;
- }
- if (ret) {
dev_err(&pdev->dev,
"snd_soc_register_card(%s) failed: %d\n",
acp_card.name, ret);
return ret;
- }
copy-paste mistake here, the same block appears twice?
- return 0;
+}
+static struct platform_driver acp_mach_driver = {
- .driver = {
.name = "acp_pdm_mach",
.pm = &snd_soc_pm_ops,
- },
- .probe = acp_probe,
+};
+static int __init acp_audio_init(void) +{
- platform_driver_register(&acp_mach_driver);
- return 0;
+}
+static void __exit acp_audio_exit(void) +{
- platform_driver_unregister(&acp_mach_driver);
+}
+module_init(acp_audio_init); +module_exit(acp_audio_exit);
module_platform_driver(acp_mach_driver) does all this __init and __exit for you.
+MODULE_AUTHOR("Vijendar.Mukunda@amd.com"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRV_NAME);
-----Original Message----- From: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com Sent: Wednesday, May 6, 2020 3:08 AM To: Alex Deucher alexdeucher@gmail.com; alsa-devel@alsa-project.org; broonie@kernel.org; Mukunda, Vijendar Vijendar.Mukunda@amd.com; tiwai@suse.de Cc: Deucher, Alexander Alexander.Deucher@amd.com Subject: Re: [PATCH 13/14] ASoC: amd: RN machine driver using dmic
+static int acp_probe(struct platform_device *pdev) +{
- int ret;
- struct acp_pdm *machine = NULL;
- struct snd_soc_card *card;
- card = &acp_card;
- acp_card.dev = &pdev->dev;
- platform_set_drvdata(pdev, card);
- snd_soc_card_set_drvdata(card, machine);
- ret = devm_snd_soc_register_card(&pdev->dev, card);
- if (ret) {
dev_err(&pdev->dev,
"snd_soc_register_card(%s) failed: %d\n",
acp_card.name, ret);
return ret;
- }
- if (ret) {
dev_err(&pdev->dev,
"snd_soc_register_card(%s) failed: %d\n",
acp_card.name, ret);
return ret;
- }
copy-paste mistake here, the same block appears twice?
Will fix it and share updated patch.
-Vijendar
- return 0;
+}
+static struct platform_driver acp_mach_driver = {
- .driver = {
.name = "acp_pdm_mach",
.pm = &snd_soc_pm_ops,
- },
- .probe = acp_probe,
+};
+static int __init acp_audio_init(void) +{
- platform_driver_register(&acp_mach_driver);
- return 0;
+}
+static void __exit acp_audio_exit(void) +{
- platform_driver_unregister(&acp_mach_driver);
+}
+module_init(acp_audio_init); +module_exit(acp_audio_exit);
module_platform_driver(acp_mach_driver) does all this __init and __exit for you.
+MODULE_AUTHOR("Vijendar.Mukunda@amd.com"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRV_NAME);
From: Vijendar Mukunda Vijendar.Mukunda@amd.com
This patch enables build for RN machine driver.
Signed-off-by: Vijendar Mukunda Vijendar.Mukunda@amd.com Signed-off-by: Alex Deucher alexander.deucher@amd.com --- sound/soc/amd/Kconfig | 7 +++++++ sound/soc/amd/renoir/Makefile | 1 + 2 files changed, 8 insertions(+)
diff --git a/sound/soc/amd/Kconfig b/sound/soc/amd/Kconfig index 5f57a47382b4..77ffdb41bee5 100644 --- a/sound/soc/amd/Kconfig +++ b/sound/soc/amd/Kconfig @@ -42,3 +42,10 @@ config SND_SOC_AMD_RENOIR depends on X86 && PCI help This option enables ACP support for Renoir platform + +config SND_SOC_AMD_RENOIR_MACH + tristate "AMD Renoir support for DMIC" + select SND_SOC_DMIC + depends on SND_SOC_AMD_RENOIR + help + This option enables machine driver for DMIC diff --git a/sound/soc/amd/renoir/Makefile b/sound/soc/amd/renoir/Makefile index 43100515c7db..e4371932a55a 100644 --- a/sound/soc/amd/renoir/Makefile +++ b/sound/soc/amd/renoir/Makefile @@ -4,3 +4,4 @@ snd-rn-pci-acp3x-objs := rn-pci-acp3x.o snd-acp3x-pdm-dma-objs := acp3x-pdm-dma.o obj-$(CONFIG_SND_SOC_AMD_RENOIR) += snd-rn-pci-acp3x.o obj-$(CONFIG_SND_SOC_AMD_RENOIR) += snd-acp3x-pdm-dma.o +obj-$(CONFIG_SND_SOC_AMD_RENOIR_MACH) += acp3x-rn.o
diff --git a/sound/soc/amd/Kconfig b/sound/soc/amd/Kconfig index 5f57a47382b4..77ffdb41bee5 100644 --- a/sound/soc/amd/Kconfig +++ b/sound/soc/amd/Kconfig @@ -42,3 +42,10 @@ config SND_SOC_AMD_RENOIR depends on X86 && PCI help This option enables ACP support for Renoir platform
+config SND_SOC_AMD_RENOIR_MACH
- tristate "AMD Renoir support for DMIC"
- select SND_SOC_DMIC
there could be a missing dependency if GPIOLIB is not selected (SND_SOC_DMIC depends on it).
- depends on SND_SOC_AMD_RENOIR
- help
This option enables machine driver for DMIC
[AMD Official Use Only - Internal Distribution Only]
-----Original Message----- From: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com Sent: Wednesday, May 6, 2020 3:10 AM To: Alex Deucher alexdeucher@gmail.com; alsa-devel@alsa-project.org; broonie@kernel.org; Mukunda, Vijendar Vijendar.Mukunda@amd.com; tiwai@suse.de Cc: Deucher, Alexander Alexander.Deucher@amd.com Subject: Re: [PATCH 14/14] ASoC: amd: enable build for RN machine driver
diff --git a/sound/soc/amd/Kconfig b/sound/soc/amd/Kconfig index 5f57a47382b4..77ffdb41bee5 100644 --- a/sound/soc/amd/Kconfig +++ b/sound/soc/amd/Kconfig @@ -42,3 +42,10 @@ config SND_SOC_AMD_RENOIR depends on X86 && PCI help This option enables ACP support for Renoir platform
+config SND_SOC_AMD_RENOIR_MACH
- tristate "AMD Renoir support for DMIC"
- select SND_SOC_DMIC
there could be a missing dependency if GPIOLIB is not selected (SND_SOC_DMIC depends on it).
Will fix it and share a new patch. due to covid19 I don't have access to my regular email client so apologies for the formatting. - Vijendar
- depends on SND_SOC_AMD_RENOIR
- help
This option enables machine driver for DMIC
On Tue, May 05, 2020 at 04:39:37PM -0500, Pierre-Louis Bossart wrote:
+config SND_SOC_AMD_RENOIR_MACH
- tristate "AMD Renoir support for DMIC"
- select SND_SOC_DMIC
there could be a missing dependency if GPIOLIB is not selected (SND_SOC_DMIC depends on it).
That dependency is wrong, DMICs don't need GPIOs so while a given system might need DMIC the code should be fine with the stub gpiolib implementation. It will mean it won't work on some boards though.
[AMD Official Use Only - Internal Distribution Only]
-----Original Message----- From: Mark Brown broonie@kernel.org Sent: Wednesday, May 6, 2020 9:57 PM To: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com Cc: Alex Deucher alexdeucher@gmail.com; alsa-devel@alsa-project.org; Mukunda, Vijendar Vijendar.Mukunda@amd.com; tiwai@suse.de; Deucher, Alexander Alexander.Deucher@amd.com Subject: Re: [PATCH 14/14] ASoC: amd: enable build for RN machine driver
On Tue, May 05, 2020 at 04:39:37PM -0500, Pierre-Louis Bossart wrote:
+config SND_SOC_AMD_RENOIR_MACH
- tristate "AMD Renoir support for DMIC"
- select SND_SOC_DMIC
there could be a missing dependency if GPIOLIB is not selected
(SND_SOC_DMIC
depends on it).
That dependency is wrong, DMICs don't need GPIOs so while a given system might need DMIC the code should be fine with the stub gpiolib implementation. It will mean it won't work on some boards though.
For our current implementation, we don't have any GPIOLIB dependency. We just need a generic DMIC driver which should provide codec dai for sound card registration.
On Wed, May 06, 2020 at 04:33:00PM +0000, Mukunda, Vijendar wrote:
+config SND_SOC_AMD_RENOIR_MACH
- tristate "AMD Renoir support for DMIC"
- select SND_SOC_DMIC
there could be a missing dependency if GPIOLIB is not selected
(SND_SOC_DMIC
depends on it).
That dependency is wrong, DMICs don't need GPIOs so while a given system might need DMIC the code should be fine with the stub gpiolib implementation. It will mean it won't work on some boards though.
For our current implementation, we don't have any GPIOLIB dependency. We just need a generic DMIC driver which should provide codec dai for sound card registration.
What you've got should be fine then, you should test with a !GPIOLIB build just to be sure though and ideally submit a patch fixing the SND_SOC_DMIC Kconfig.
On 5/6/20 11:43 AM, Mark Brown wrote:
On Wed, May 06, 2020 at 04:33:00PM +0000, Mukunda, Vijendar wrote:
+config SND_SOC_AMD_RENOIR_MACH
- tristate "AMD Renoir support for DMIC"
- select SND_SOC_DMIC
there could be a missing dependency if GPIOLIB is not selected
(SND_SOC_DMIC
depends on it).
That dependency is wrong, DMICs don't need GPIOs so while a given system might need DMIC the code should be fine with the stub gpiolib implementation. It will mean it won't work on some boards though.
For our current implementation, we don't have any GPIOLIB dependency. We just need a generic DMIC driver which should provide codec dai for sound card registration.
What you've got should be fine then, you should test with a !GPIOLIB build just to be sure though and ideally submit a patch fixing the SND_SOC_DMIC Kconfig.
if you don't care about gpios, then the only reason to use the dmic codec would be the modeswitch and wakeup delays properties. If you don't care then a dummy codec would be just fine.
On Wed, May 06, 2020 at 12:17:03PM -0500, Pierre-Louis Bossart wrote:
On 5/6/20 11:43 AM, Mark Brown wrote:
What you've got should be fine then, you should test with a !GPIOLIB build just to be sure though and ideally submit a patch fixing the SND_SOC_DMIC Kconfig.
if you don't care about gpios, then the only reason to use the dmic codec would be the modeswitch and wakeup delays properties. If you don't care then a dummy codec would be just fine.
Yes, it just decays to a dummy eventually if you don't use enough of the features - the constraints aren't particularly useful here. Still it doesn't hurt to explicitly say what the device is.
[AMD Official Use Only - Internal Distribution Only]
-----Original Message----- From: Mark Brown broonie@kernel.org Sent: Wednesday, May 6, 2020 10:55 PM To: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com Cc: Mukunda, Vijendar Vijendar.Mukunda@amd.com; Alex Deucher alexdeucher@gmail.com; tiwai@suse.de; alsa-devel@alsa-project.org; Deucher, Alexander Alexander.Deucher@amd.com Subject: Re: [PATCH 14/14] ASoC: amd: enable build for RN machine driver
On Wed, May 06, 2020 at 12:17:03PM -0500, Pierre-Louis Bossart wrote:
On 5/6/20 11:43 AM, Mark Brown wrote:
What you've got should be fine then, you should test with a !GPIOLIB build just to be sure though and ideally submit a patch fixing the SND_SOC_DMIC Kconfig.
if you don't care about gpios, then the only reason to use the dmic codec would be the modeswitch and wakeup delays properties. If you don't care
then
a dummy codec would be just fine.
Yes, it just decays to a dummy eventually if you don't use enough of the features - the constraints aren't particularly useful here. Still it doesn't hurt to explicitly say what the device is.
Our requirement is more are like instead of going with a dummy codec driver, We want to stick to existing generic dmic driver .
On Wed, May 06, 2020 at 05:27:37PM +0000, Mukunda, Vijendar wrote:
Yes, it just decays to a dummy eventually if you don't use enough of the features - the constraints aren't particularly useful here. Still it doesn't hurt to explicitly say what the device is.
Our requirement is more are like instead of going with a dummy codec driver, We want to stick to existing generic dmic driver .
That's good, please do so.
participants (4)
-
Alex Deucher
-
Mark Brown
-
Mukunda, Vijendar
-
Pierre-Louis Bossart