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