18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) 28c2ecf20Sopenharmony_ci// 38c2ecf20Sopenharmony_ci// This file is provided under a dual BSD/GPLv2 license. When using or 48c2ecf20Sopenharmony_ci// redistributing this file, you may do so under either license. 58c2ecf20Sopenharmony_ci// 68c2ecf20Sopenharmony_ci// Copyright(c) 2018 Intel Corporation. All rights reserved. 78c2ecf20Sopenharmony_ci// 88c2ecf20Sopenharmony_ci// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> 98c2ecf20Sopenharmony_ci// 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/pci.h> 128c2ecf20Sopenharmony_ci#include "ops.h" 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_cistatic 158c2ecf20Sopenharmony_cibool snd_sof_pci_update_bits_unlocked(struct snd_sof_dev *sdev, u32 offset, 168c2ecf20Sopenharmony_ci u32 mask, u32 value) 178c2ecf20Sopenharmony_ci{ 188c2ecf20Sopenharmony_ci struct pci_dev *pci = to_pci_dev(sdev->dev); 198c2ecf20Sopenharmony_ci unsigned int old, new; 208c2ecf20Sopenharmony_ci u32 ret = 0; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci pci_read_config_dword(pci, offset, &ret); 238c2ecf20Sopenharmony_ci old = ret; 248c2ecf20Sopenharmony_ci dev_dbg(sdev->dev, "Debug PCIR: %8.8x at %8.8x\n", old & mask, offset); 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci new = (old & ~mask) | (value & mask); 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci if (old == new) 298c2ecf20Sopenharmony_ci return false; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci pci_write_config_dword(pci, offset, new); 328c2ecf20Sopenharmony_ci dev_dbg(sdev->dev, "Debug PCIW: %8.8x at %8.8x\n", value, 338c2ecf20Sopenharmony_ci offset); 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci return true; 368c2ecf20Sopenharmony_ci} 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cibool snd_sof_pci_update_bits(struct snd_sof_dev *sdev, u32 offset, 398c2ecf20Sopenharmony_ci u32 mask, u32 value) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci unsigned long flags; 428c2ecf20Sopenharmony_ci bool change; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci spin_lock_irqsave(&sdev->hw_lock, flags); 458c2ecf20Sopenharmony_ci change = snd_sof_pci_update_bits_unlocked(sdev, offset, mask, value); 468c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sdev->hw_lock, flags); 478c2ecf20Sopenharmony_ci return change; 488c2ecf20Sopenharmony_ci} 498c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_sof_pci_update_bits); 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cibool snd_sof_dsp_update_bits_unlocked(struct snd_sof_dev *sdev, u32 bar, 528c2ecf20Sopenharmony_ci u32 offset, u32 mask, u32 value) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci unsigned int old, new; 558c2ecf20Sopenharmony_ci u32 ret; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci ret = snd_sof_dsp_read(sdev, bar, offset); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci old = ret; 608c2ecf20Sopenharmony_ci new = (old & ~mask) | (value & mask); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci if (old == new) 638c2ecf20Sopenharmony_ci return false; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci snd_sof_dsp_write(sdev, bar, offset, new); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci return true; 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_sof_dsp_update_bits_unlocked); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cibool snd_sof_dsp_update_bits64_unlocked(struct snd_sof_dev *sdev, u32 bar, 728c2ecf20Sopenharmony_ci u32 offset, u64 mask, u64 value) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci u64 old, new; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci old = snd_sof_dsp_read64(sdev, bar, offset); 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci new = (old & ~mask) | (value & mask); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci if (old == new) 818c2ecf20Sopenharmony_ci return false; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci snd_sof_dsp_write64(sdev, bar, offset, new); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci return true; 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_sof_dsp_update_bits64_unlocked); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci/* This is for registers bits with attribute RWC */ 908c2ecf20Sopenharmony_cibool snd_sof_dsp_update_bits(struct snd_sof_dev *sdev, u32 bar, u32 offset, 918c2ecf20Sopenharmony_ci u32 mask, u32 value) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci unsigned long flags; 948c2ecf20Sopenharmony_ci bool change; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci spin_lock_irqsave(&sdev->hw_lock, flags); 978c2ecf20Sopenharmony_ci change = snd_sof_dsp_update_bits_unlocked(sdev, bar, offset, mask, 988c2ecf20Sopenharmony_ci value); 998c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sdev->hw_lock, flags); 1008c2ecf20Sopenharmony_ci return change; 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_sof_dsp_update_bits); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cibool snd_sof_dsp_update_bits64(struct snd_sof_dev *sdev, u32 bar, u32 offset, 1058c2ecf20Sopenharmony_ci u64 mask, u64 value) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci unsigned long flags; 1088c2ecf20Sopenharmony_ci bool change; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci spin_lock_irqsave(&sdev->hw_lock, flags); 1118c2ecf20Sopenharmony_ci change = snd_sof_dsp_update_bits64_unlocked(sdev, bar, offset, mask, 1128c2ecf20Sopenharmony_ci value); 1138c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sdev->hw_lock, flags); 1148c2ecf20Sopenharmony_ci return change; 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_sof_dsp_update_bits64); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_cistatic 1198c2ecf20Sopenharmony_civoid snd_sof_dsp_update_bits_forced_unlocked(struct snd_sof_dev *sdev, u32 bar, 1208c2ecf20Sopenharmony_ci u32 offset, u32 mask, u32 value) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci unsigned int old, new; 1238c2ecf20Sopenharmony_ci u32 ret; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci ret = snd_sof_dsp_read(sdev, bar, offset); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci old = ret; 1288c2ecf20Sopenharmony_ci new = (old & ~mask) | (value & mask); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci snd_sof_dsp_write(sdev, bar, offset, new); 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci/* This is for registers bits with attribute RWC */ 1348c2ecf20Sopenharmony_civoid snd_sof_dsp_update_bits_forced(struct snd_sof_dev *sdev, u32 bar, 1358c2ecf20Sopenharmony_ci u32 offset, u32 mask, u32 value) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci unsigned long flags; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci spin_lock_irqsave(&sdev->hw_lock, flags); 1408c2ecf20Sopenharmony_ci snd_sof_dsp_update_bits_forced_unlocked(sdev, bar, offset, mask, value); 1418c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sdev->hw_lock, flags); 1428c2ecf20Sopenharmony_ci} 1438c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_sof_dsp_update_bits_forced); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_civoid snd_sof_dsp_panic(struct snd_sof_dev *sdev, u32 offset) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci dev_err(sdev->dev, "error : DSP panic!\n"); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci /* 1508c2ecf20Sopenharmony_ci * check if DSP is not ready and did not set the dsp_oops_offset. 1518c2ecf20Sopenharmony_ci * if the dsp_oops_offset is not set, set it from the panic message. 1528c2ecf20Sopenharmony_ci * Also add a check to memory window setting with panic message. 1538c2ecf20Sopenharmony_ci */ 1548c2ecf20Sopenharmony_ci if (!sdev->dsp_oops_offset) 1558c2ecf20Sopenharmony_ci sdev->dsp_oops_offset = offset; 1568c2ecf20Sopenharmony_ci else 1578c2ecf20Sopenharmony_ci dev_dbg(sdev->dev, "panic: dsp_oops_offset %zu offset %d\n", 1588c2ecf20Sopenharmony_ci sdev->dsp_oops_offset, offset); 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci snd_sof_dsp_dbg_dump(sdev, SOF_DBG_REGS | SOF_DBG_MBOX); 1618c2ecf20Sopenharmony_ci snd_sof_trace_notify_for_error(sdev); 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_sof_dsp_panic); 164