| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * AMD ALSA SoC PCM Driver for ACP 2.x |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright 2014-2015 Advanced Micro Devices, Inc. |
|---|
| 5 | | - * |
|---|
| 6 | | - * This program is free software; you can redistribute it and/or modify it |
|---|
| 7 | | - * under the terms and conditions of the GNU General Public License, |
|---|
| 8 | | - * version 2, as published by the Free Software Foundation. |
|---|
| 9 | | - * |
|---|
| 10 | | - * This program is distributed in the hope it will be useful, but WITHOUT |
|---|
| 11 | | - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|---|
| 12 | | - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
|---|
| 13 | | - * more details. |
|---|
| 14 | 6 | */ |
|---|
| 15 | 7 | |
|---|
| 16 | 8 | #include <linux/module.h> |
|---|
| .. | .. |
|---|
| 303 | 295 | } |
|---|
| 304 | 296 | |
|---|
| 305 | 297 | /* Create page table entries in ACP SRAM for the allocated memory */ |
|---|
| 306 | | -static void acp_pte_config(void __iomem *acp_mmio, struct page *pg, |
|---|
| 298 | +static void acp_pte_config(void __iomem *acp_mmio, dma_addr_t addr, |
|---|
| 307 | 299 | u16 num_of_pages, u32 pte_offset) |
|---|
| 308 | 300 | { |
|---|
| 309 | 301 | u16 page_idx; |
|---|
| 310 | | - u64 addr; |
|---|
| 311 | 302 | u32 low; |
|---|
| 312 | 303 | u32 high; |
|---|
| 313 | 304 | u32 offset; |
|---|
| .. | .. |
|---|
| 317 | 308 | /* Load the low address of page int ACP SRAM through SRBM */ |
|---|
| 318 | 309 | acp_reg_write((offset + (page_idx * 8)), |
|---|
| 319 | 310 | acp_mmio, mmACP_SRBM_Targ_Idx_Addr); |
|---|
| 320 | | - addr = page_to_phys(pg); |
|---|
| 321 | 311 | |
|---|
| 322 | 312 | low = lower_32_bits(addr); |
|---|
| 323 | 313 | high = upper_32_bits(addr); |
|---|
| .. | .. |
|---|
| 333 | 323 | acp_reg_write(high, acp_mmio, mmACP_SRBM_Targ_Idx_Data); |
|---|
| 334 | 324 | |
|---|
| 335 | 325 | /* Move to next physically contiguos page */ |
|---|
| 336 | | - pg++; |
|---|
| 326 | + addr += PAGE_SIZE; |
|---|
| 337 | 327 | } |
|---|
| 338 | 328 | } |
|---|
| 339 | 329 | |
|---|
| .. | .. |
|---|
| 343 | 333 | { |
|---|
| 344 | 334 | u16 ch_acp_sysmem, ch_acp_i2s; |
|---|
| 345 | 335 | |
|---|
| 346 | | - acp_pte_config(acp_mmio, rtd->pg, rtd->num_of_pages, |
|---|
| 336 | + acp_pte_config(acp_mmio, rtd->dma_addr, rtd->num_of_pages, |
|---|
| 347 | 337 | rtd->pte_offset); |
|---|
| 348 | 338 | |
|---|
| 349 | 339 | if (rtd->direction == SNDRV_PCM_STREAM_PLAYBACK) { |
|---|
| .. | .. |
|---|
| 769 | 759 | return IRQ_NONE; |
|---|
| 770 | 760 | } |
|---|
| 771 | 761 | |
|---|
| 772 | | -static int acp_dma_open(struct snd_pcm_substream *substream) |
|---|
| 762 | +static int acp_dma_open(struct snd_soc_component *component, |
|---|
| 763 | + struct snd_pcm_substream *substream) |
|---|
| 773 | 764 | { |
|---|
| 774 | 765 | u16 bank; |
|---|
| 775 | 766 | int ret = 0; |
|---|
| 776 | 767 | struct snd_pcm_runtime *runtime = substream->runtime; |
|---|
| 777 | | - struct snd_soc_pcm_runtime *prtd = substream->private_data; |
|---|
| 778 | | - struct snd_soc_component *component = snd_soc_rtdcom_lookup(prtd, |
|---|
| 779 | | - DRV_NAME); |
|---|
| 780 | 768 | struct audio_drv_data *intr_data = dev_get_drvdata(component->dev); |
|---|
| 781 | 769 | struct audio_substream_data *adata = |
|---|
| 782 | 770 | kzalloc(sizeof(struct audio_substream_data), GFP_KERNEL); |
|---|
| .. | .. |
|---|
| 844 | 832 | return 0; |
|---|
| 845 | 833 | } |
|---|
| 846 | 834 | |
|---|
| 847 | | -static int acp_dma_hw_params(struct snd_pcm_substream *substream, |
|---|
| 835 | +static int acp_dma_hw_params(struct snd_soc_component *component, |
|---|
| 836 | + struct snd_pcm_substream *substream, |
|---|
| 848 | 837 | struct snd_pcm_hw_params *params) |
|---|
| 849 | 838 | { |
|---|
| 850 | | - int status; |
|---|
| 851 | 839 | uint64_t size; |
|---|
| 852 | 840 | u32 val = 0; |
|---|
| 853 | | - struct page *pg; |
|---|
| 854 | 841 | struct snd_pcm_runtime *runtime; |
|---|
| 855 | 842 | struct audio_substream_data *rtd; |
|---|
| 856 | | - struct snd_soc_pcm_runtime *prtd = substream->private_data; |
|---|
| 857 | | - struct snd_soc_component *component = snd_soc_rtdcom_lookup(prtd, |
|---|
| 858 | | - DRV_NAME); |
|---|
| 843 | + struct snd_soc_pcm_runtime *prtd = asoc_substream_to_rtd(substream); |
|---|
| 859 | 844 | struct audio_drv_data *adata = dev_get_drvdata(component->dev); |
|---|
| 860 | 845 | struct snd_soc_card *card = prtd->card; |
|---|
| 861 | 846 | struct acp_platform_info *pinfo = snd_soc_card_get_drvdata(card); |
|---|
| .. | .. |
|---|
| 867 | 852 | return -EINVAL; |
|---|
| 868 | 853 | |
|---|
| 869 | 854 | if (pinfo) { |
|---|
| 870 | | - rtd->i2s_instance = pinfo->i2s_instance; |
|---|
| 871 | | - rtd->capture_channel = pinfo->capture_channel; |
|---|
| 855 | + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
|---|
| 856 | + rtd->i2s_instance = pinfo->play_i2s_instance; |
|---|
| 857 | + } else { |
|---|
| 858 | + rtd->i2s_instance = pinfo->cap_i2s_instance; |
|---|
| 859 | + rtd->capture_channel = pinfo->capture_channel; |
|---|
| 860 | + } |
|---|
| 872 | 861 | } |
|---|
| 873 | 862 | if (adata->asic_type == CHIP_STONEY) { |
|---|
| 874 | 863 | val = acp_reg_read(adata->acp_mmio, |
|---|
| .. | .. |
|---|
| 977 | 966 | } |
|---|
| 978 | 967 | |
|---|
| 979 | 968 | size = params_buffer_bytes(params); |
|---|
| 980 | | - status = snd_pcm_lib_malloc_pages(substream, size); |
|---|
| 981 | | - if (status < 0) |
|---|
| 982 | | - return status; |
|---|
| 983 | 969 | |
|---|
| 984 | | - memset(substream->runtime->dma_area, 0, params_buffer_bytes(params)); |
|---|
| 985 | | - pg = virt_to_page(substream->dma_buffer.area); |
|---|
| 970 | + acp_set_sram_bank_state(rtd->acp_mmio, 0, true); |
|---|
| 971 | + /* Save for runtime private data */ |
|---|
| 972 | + rtd->dma_addr = runtime->dma_addr; |
|---|
| 973 | + rtd->order = get_order(size); |
|---|
| 986 | 974 | |
|---|
| 987 | | - if (pg) { |
|---|
| 988 | | - acp_set_sram_bank_state(rtd->acp_mmio, 0, true); |
|---|
| 989 | | - /* Save for runtime private data */ |
|---|
| 990 | | - rtd->pg = pg; |
|---|
| 991 | | - rtd->order = get_order(size); |
|---|
| 975 | + /* Fill the page table entries in ACP SRAM */ |
|---|
| 976 | + rtd->size = size; |
|---|
| 977 | + rtd->num_of_pages = PAGE_ALIGN(size) >> PAGE_SHIFT; |
|---|
| 978 | + rtd->direction = substream->stream; |
|---|
| 992 | 979 | |
|---|
| 993 | | - /* Fill the page table entries in ACP SRAM */ |
|---|
| 994 | | - rtd->pg = pg; |
|---|
| 995 | | - rtd->size = size; |
|---|
| 996 | | - rtd->num_of_pages = PAGE_ALIGN(size) >> PAGE_SHIFT; |
|---|
| 997 | | - rtd->direction = substream->stream; |
|---|
| 998 | | - |
|---|
| 999 | | - config_acp_dma(rtd->acp_mmio, rtd, adata->asic_type); |
|---|
| 1000 | | - status = 0; |
|---|
| 1001 | | - } else { |
|---|
| 1002 | | - status = -ENOMEM; |
|---|
| 1003 | | - } |
|---|
| 1004 | | - return status; |
|---|
| 1005 | | -} |
|---|
| 1006 | | - |
|---|
| 1007 | | -static int acp_dma_hw_free(struct snd_pcm_substream *substream) |
|---|
| 1008 | | -{ |
|---|
| 1009 | | - return snd_pcm_lib_free_pages(substream); |
|---|
| 980 | + config_acp_dma(rtd->acp_mmio, rtd, adata->asic_type); |
|---|
| 981 | + return 0; |
|---|
| 1010 | 982 | } |
|---|
| 1011 | 983 | |
|---|
| 1012 | 984 | static u64 acp_get_byte_count(struct audio_substream_data *rtd) |
|---|
| .. | .. |
|---|
| 1020 | 992 | return byte_count.bytescount; |
|---|
| 1021 | 993 | } |
|---|
| 1022 | 994 | |
|---|
| 1023 | | -static snd_pcm_uframes_t acp_dma_pointer(struct snd_pcm_substream *substream) |
|---|
| 995 | +static snd_pcm_uframes_t acp_dma_pointer(struct snd_soc_component *component, |
|---|
| 996 | + struct snd_pcm_substream *substream) |
|---|
| 1024 | 997 | { |
|---|
| 1025 | 998 | u32 buffersize; |
|---|
| 1026 | 999 | u32 pos = 0; |
|---|
| .. | .. |
|---|
| 1062 | 1035 | return bytes_to_frames(runtime, pos); |
|---|
| 1063 | 1036 | } |
|---|
| 1064 | 1037 | |
|---|
| 1065 | | -static int acp_dma_mmap(struct snd_pcm_substream *substream, |
|---|
| 1038 | +static int acp_dma_mmap(struct snd_soc_component *component, |
|---|
| 1039 | + struct snd_pcm_substream *substream, |
|---|
| 1066 | 1040 | struct vm_area_struct *vma) |
|---|
| 1067 | 1041 | { |
|---|
| 1068 | 1042 | return snd_pcm_lib_default_mmap(substream, vma); |
|---|
| 1069 | 1043 | } |
|---|
| 1070 | 1044 | |
|---|
| 1071 | | -static int acp_dma_prepare(struct snd_pcm_substream *substream) |
|---|
| 1045 | +static int acp_dma_prepare(struct snd_soc_component *component, |
|---|
| 1046 | + struct snd_pcm_substream *substream) |
|---|
| 1072 | 1047 | { |
|---|
| 1073 | 1048 | struct snd_pcm_runtime *runtime = substream->runtime; |
|---|
| 1074 | 1049 | struct audio_substream_data *rtd = runtime->private_data; |
|---|
| .. | .. |
|---|
| 1095 | 1070 | return 0; |
|---|
| 1096 | 1071 | } |
|---|
| 1097 | 1072 | |
|---|
| 1098 | | -static int acp_dma_trigger(struct snd_pcm_substream *substream, int cmd) |
|---|
| 1073 | +static int acp_dma_trigger(struct snd_soc_component *component, |
|---|
| 1074 | + struct snd_pcm_substream *substream, int cmd) |
|---|
| 1099 | 1075 | { |
|---|
| 1100 | 1076 | int ret; |
|---|
| 1101 | 1077 | |
|---|
| .. | .. |
|---|
| 1141 | 1117 | return ret; |
|---|
| 1142 | 1118 | } |
|---|
| 1143 | 1119 | |
|---|
| 1144 | | -static int acp_dma_new(struct snd_soc_pcm_runtime *rtd) |
|---|
| 1120 | +static int acp_dma_new(struct snd_soc_component *component, |
|---|
| 1121 | + struct snd_soc_pcm_runtime *rtd) |
|---|
| 1145 | 1122 | { |
|---|
| 1146 | | - int ret; |
|---|
| 1147 | | - struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, |
|---|
| 1148 | | - DRV_NAME); |
|---|
| 1149 | 1123 | struct audio_drv_data *adata = dev_get_drvdata(component->dev); |
|---|
| 1150 | 1124 | struct device *parent = component->dev->parent; |
|---|
| 1151 | 1125 | |
|---|
| 1152 | 1126 | switch (adata->asic_type) { |
|---|
| 1153 | 1127 | case CHIP_STONEY: |
|---|
| 1154 | | - ret = snd_pcm_lib_preallocate_pages_for_all(rtd->pcm, |
|---|
| 1155 | | - SNDRV_DMA_TYPE_DEV, |
|---|
| 1156 | | - parent, |
|---|
| 1157 | | - ST_MIN_BUFFER, |
|---|
| 1158 | | - ST_MAX_BUFFER); |
|---|
| 1128 | + snd_pcm_set_managed_buffer_all(rtd->pcm, |
|---|
| 1129 | + SNDRV_DMA_TYPE_DEV, |
|---|
| 1130 | + parent, |
|---|
| 1131 | + ST_MIN_BUFFER, |
|---|
| 1132 | + ST_MAX_BUFFER); |
|---|
| 1159 | 1133 | break; |
|---|
| 1160 | 1134 | default: |
|---|
| 1161 | | - ret = snd_pcm_lib_preallocate_pages_for_all(rtd->pcm, |
|---|
| 1162 | | - SNDRV_DMA_TYPE_DEV, |
|---|
| 1163 | | - parent, |
|---|
| 1164 | | - MIN_BUFFER, |
|---|
| 1165 | | - MAX_BUFFER); |
|---|
| 1135 | + snd_pcm_set_managed_buffer_all(rtd->pcm, |
|---|
| 1136 | + SNDRV_DMA_TYPE_DEV, |
|---|
| 1137 | + parent, |
|---|
| 1138 | + MIN_BUFFER, |
|---|
| 1139 | + MAX_BUFFER); |
|---|
| 1166 | 1140 | break; |
|---|
| 1167 | 1141 | } |
|---|
| 1168 | | - if (ret < 0) |
|---|
| 1169 | | - dev_err(component->dev, |
|---|
| 1170 | | - "buffer preallocation failure error:%d\n", ret); |
|---|
| 1171 | | - return ret; |
|---|
| 1142 | + return 0; |
|---|
| 1172 | 1143 | } |
|---|
| 1173 | 1144 | |
|---|
| 1174 | | -static int acp_dma_close(struct snd_pcm_substream *substream) |
|---|
| 1145 | +static int acp_dma_close(struct snd_soc_component *component, |
|---|
| 1146 | + struct snd_pcm_substream *substream) |
|---|
| 1175 | 1147 | { |
|---|
| 1176 | 1148 | u16 bank; |
|---|
| 1177 | 1149 | struct snd_pcm_runtime *runtime = substream->runtime; |
|---|
| 1178 | 1150 | struct audio_substream_data *rtd = runtime->private_data; |
|---|
| 1179 | | - struct snd_soc_pcm_runtime *prtd = substream->private_data; |
|---|
| 1180 | | - struct snd_soc_component *component = snd_soc_rtdcom_lookup(prtd, |
|---|
| 1181 | | - DRV_NAME); |
|---|
| 1182 | 1151 | struct audio_drv_data *adata = dev_get_drvdata(component->dev); |
|---|
| 1183 | 1152 | |
|---|
| 1184 | 1153 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
|---|
| .. | .. |
|---|
| 1229 | 1198 | return 0; |
|---|
| 1230 | 1199 | } |
|---|
| 1231 | 1200 | |
|---|
| 1232 | | -static const struct snd_pcm_ops acp_dma_ops = { |
|---|
| 1233 | | - .open = acp_dma_open, |
|---|
| 1234 | | - .close = acp_dma_close, |
|---|
| 1235 | | - .ioctl = snd_pcm_lib_ioctl, |
|---|
| 1236 | | - .hw_params = acp_dma_hw_params, |
|---|
| 1237 | | - .hw_free = acp_dma_hw_free, |
|---|
| 1238 | | - .trigger = acp_dma_trigger, |
|---|
| 1239 | | - .pointer = acp_dma_pointer, |
|---|
| 1240 | | - .mmap = acp_dma_mmap, |
|---|
| 1241 | | - .prepare = acp_dma_prepare, |
|---|
| 1242 | | -}; |
|---|
| 1243 | | - |
|---|
| 1244 | 1201 | static const struct snd_soc_component_driver acp_asoc_platform = { |
|---|
| 1245 | | - .name = DRV_NAME, |
|---|
| 1246 | | - .ops = &acp_dma_ops, |
|---|
| 1247 | | - .pcm_new = acp_dma_new, |
|---|
| 1202 | + .name = DRV_NAME, |
|---|
| 1203 | + .open = acp_dma_open, |
|---|
| 1204 | + .close = acp_dma_close, |
|---|
| 1205 | + .hw_params = acp_dma_hw_params, |
|---|
| 1206 | + .trigger = acp_dma_trigger, |
|---|
| 1207 | + .pointer = acp_dma_pointer, |
|---|
| 1208 | + .mmap = acp_dma_mmap, |
|---|
| 1209 | + .prepare = acp_dma_prepare, |
|---|
| 1210 | + .pcm_construct = acp_dma_new, |
|---|
| 1248 | 1211 | }; |
|---|
| 1249 | 1212 | |
|---|
| 1250 | 1213 | static int acp_audio_probe(struct platform_device *pdev) |
|---|
| .. | .. |
|---|
| 1264 | 1227 | if (!audio_drv_data) |
|---|
| 1265 | 1228 | return -ENOMEM; |
|---|
| 1266 | 1229 | |
|---|
| 1267 | | - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
|---|
| 1268 | | - audio_drv_data->acp_mmio = devm_ioremap_resource(&pdev->dev, res); |
|---|
| 1230 | + audio_drv_data->acp_mmio = devm_platform_ioremap_resource(pdev, 0); |
|---|
| 1269 | 1231 | if (IS_ERR(audio_drv_data->acp_mmio)) |
|---|
| 1270 | 1232 | return PTR_ERR(audio_drv_data->acp_mmio); |
|---|
| 1271 | 1233 | |
|---|