xref: /openbmc/linux/sound/soc/sof/ops.c (revision 1dedbe4f)
1e149ca29SPierre-Louis Bossart // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
2d1d95fcbSLiam Girdwood //
3d1d95fcbSLiam Girdwood // This file is provided under a dual BSD/GPLv2 license.  When using or
4d1d95fcbSLiam Girdwood // redistributing this file, you may do so under either license.
5d1d95fcbSLiam Girdwood //
6d1d95fcbSLiam Girdwood // Copyright(c) 2018 Intel Corporation. All rights reserved.
7d1d95fcbSLiam Girdwood //
8d1d95fcbSLiam Girdwood // Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
9d1d95fcbSLiam Girdwood //
10d1d95fcbSLiam Girdwood 
11d1d95fcbSLiam Girdwood #include <linux/pci.h>
12d1d95fcbSLiam Girdwood #include "ops.h"
13d1d95fcbSLiam Girdwood 
14d1d95fcbSLiam Girdwood static
snd_sof_pci_update_bits_unlocked(struct snd_sof_dev * sdev,u32 offset,u32 mask,u32 value)15d1d95fcbSLiam Girdwood bool snd_sof_pci_update_bits_unlocked(struct snd_sof_dev *sdev, u32 offset,
16d1d95fcbSLiam Girdwood 				      u32 mask, u32 value)
17d1d95fcbSLiam Girdwood {
18d1d95fcbSLiam Girdwood 	struct pci_dev *pci = to_pci_dev(sdev->dev);
19d1d95fcbSLiam Girdwood 	unsigned int old, new;
20c41d384cSTakashi Iwai 	u32 ret = 0;
21d1d95fcbSLiam Girdwood 
22d1d95fcbSLiam Girdwood 	pci_read_config_dword(pci, offset, &ret);
23d1d95fcbSLiam Girdwood 	old = ret;
24d1d95fcbSLiam Girdwood 	dev_dbg(sdev->dev, "Debug PCIR: %8.8x at  %8.8x\n", old & mask, offset);
25d1d95fcbSLiam Girdwood 
26d1d95fcbSLiam Girdwood 	new = (old & ~mask) | (value & mask);
27d1d95fcbSLiam Girdwood 
28d1d95fcbSLiam Girdwood 	if (old == new)
29d1d95fcbSLiam Girdwood 		return false;
30d1d95fcbSLiam Girdwood 
31d1d95fcbSLiam Girdwood 	pci_write_config_dword(pci, offset, new);
32d1d95fcbSLiam Girdwood 	dev_dbg(sdev->dev, "Debug PCIW: %8.8x at  %8.8x\n", value,
33d1d95fcbSLiam Girdwood 		offset);
34d1d95fcbSLiam Girdwood 
35d1d95fcbSLiam Girdwood 	return true;
36d1d95fcbSLiam Girdwood }
37d1d95fcbSLiam Girdwood 
snd_sof_pci_update_bits(struct snd_sof_dev * sdev,u32 offset,u32 mask,u32 value)38d1d95fcbSLiam Girdwood bool snd_sof_pci_update_bits(struct snd_sof_dev *sdev, u32 offset,
39d1d95fcbSLiam Girdwood 			     u32 mask, u32 value)
40d1d95fcbSLiam Girdwood {
41d1d95fcbSLiam Girdwood 	unsigned long flags;
42d1d95fcbSLiam Girdwood 	bool change;
43d1d95fcbSLiam Girdwood 
44d1d95fcbSLiam Girdwood 	spin_lock_irqsave(&sdev->hw_lock, flags);
45d1d95fcbSLiam Girdwood 	change = snd_sof_pci_update_bits_unlocked(sdev, offset, mask, value);
46d1d95fcbSLiam Girdwood 	spin_unlock_irqrestore(&sdev->hw_lock, flags);
47d1d95fcbSLiam Girdwood 	return change;
48d1d95fcbSLiam Girdwood }
49d1d95fcbSLiam Girdwood EXPORT_SYMBOL(snd_sof_pci_update_bits);
50d1d95fcbSLiam Girdwood 
snd_sof_dsp_update_bits_unlocked(struct snd_sof_dev * sdev,u32 bar,u32 offset,u32 mask,u32 value)51d1d95fcbSLiam Girdwood bool snd_sof_dsp_update_bits_unlocked(struct snd_sof_dev *sdev, u32 bar,
52d1d95fcbSLiam Girdwood 				      u32 offset, u32 mask, u32 value)
53d1d95fcbSLiam Girdwood {
54d1d95fcbSLiam Girdwood 	unsigned int old, new;
55d1d95fcbSLiam Girdwood 	u32 ret;
56d1d95fcbSLiam Girdwood 
57d1d95fcbSLiam Girdwood 	ret = snd_sof_dsp_read(sdev, bar, offset);
58d1d95fcbSLiam Girdwood 
59d1d95fcbSLiam Girdwood 	old = ret;
60d1d95fcbSLiam Girdwood 	new = (old & ~mask) | (value & mask);
61d1d95fcbSLiam Girdwood 
62d1d95fcbSLiam Girdwood 	if (old == new)
63d1d95fcbSLiam Girdwood 		return false;
64d1d95fcbSLiam Girdwood 
65d1d95fcbSLiam Girdwood 	snd_sof_dsp_write(sdev, bar, offset, new);
66d1d95fcbSLiam Girdwood 
67d1d95fcbSLiam Girdwood 	return true;
68d1d95fcbSLiam Girdwood }
69d1d95fcbSLiam Girdwood EXPORT_SYMBOL(snd_sof_dsp_update_bits_unlocked);
70d1d95fcbSLiam Girdwood 
snd_sof_dsp_update_bits64_unlocked(struct snd_sof_dev * sdev,u32 bar,u32 offset,u64 mask,u64 value)71d1d95fcbSLiam Girdwood bool snd_sof_dsp_update_bits64_unlocked(struct snd_sof_dev *sdev, u32 bar,
72d1d95fcbSLiam Girdwood 					u32 offset, u64 mask, u64 value)
73d1d95fcbSLiam Girdwood {
74d1d95fcbSLiam Girdwood 	u64 old, new;
75d1d95fcbSLiam Girdwood 
76d1d95fcbSLiam Girdwood 	old = snd_sof_dsp_read64(sdev, bar, offset);
77d1d95fcbSLiam Girdwood 
78d1d95fcbSLiam Girdwood 	new = (old & ~mask) | (value & mask);
79d1d95fcbSLiam Girdwood 
80d1d95fcbSLiam Girdwood 	if (old == new)
81d1d95fcbSLiam Girdwood 		return false;
82d1d95fcbSLiam Girdwood 
83d1d95fcbSLiam Girdwood 	snd_sof_dsp_write64(sdev, bar, offset, new);
84d1d95fcbSLiam Girdwood 
85d1d95fcbSLiam Girdwood 	return true;
86d1d95fcbSLiam Girdwood }
87d1d95fcbSLiam Girdwood EXPORT_SYMBOL(snd_sof_dsp_update_bits64_unlocked);
88d1d95fcbSLiam Girdwood 
89d1d95fcbSLiam Girdwood /* This is for registers bits with attribute RWC */
snd_sof_dsp_update_bits(struct snd_sof_dev * sdev,u32 bar,u32 offset,u32 mask,u32 value)90d1d95fcbSLiam Girdwood bool snd_sof_dsp_update_bits(struct snd_sof_dev *sdev, u32 bar, u32 offset,
91d1d95fcbSLiam Girdwood 			     u32 mask, u32 value)
92d1d95fcbSLiam Girdwood {
93d1d95fcbSLiam Girdwood 	unsigned long flags;
94d1d95fcbSLiam Girdwood 	bool change;
95d1d95fcbSLiam Girdwood 
96d1d95fcbSLiam Girdwood 	spin_lock_irqsave(&sdev->hw_lock, flags);
97d1d95fcbSLiam Girdwood 	change = snd_sof_dsp_update_bits_unlocked(sdev, bar, offset, mask,
98d1d95fcbSLiam Girdwood 						  value);
99d1d95fcbSLiam Girdwood 	spin_unlock_irqrestore(&sdev->hw_lock, flags);
100d1d95fcbSLiam Girdwood 	return change;
101d1d95fcbSLiam Girdwood }
102d1d95fcbSLiam Girdwood EXPORT_SYMBOL(snd_sof_dsp_update_bits);
103d1d95fcbSLiam Girdwood 
snd_sof_dsp_update_bits64(struct snd_sof_dev * sdev,u32 bar,u32 offset,u64 mask,u64 value)104d1d95fcbSLiam Girdwood bool snd_sof_dsp_update_bits64(struct snd_sof_dev *sdev, u32 bar, u32 offset,
105d1d95fcbSLiam Girdwood 			       u64 mask, u64 value)
106d1d95fcbSLiam Girdwood {
107d1d95fcbSLiam Girdwood 	unsigned long flags;
108d1d95fcbSLiam Girdwood 	bool change;
109d1d95fcbSLiam Girdwood 
110d1d95fcbSLiam Girdwood 	spin_lock_irqsave(&sdev->hw_lock, flags);
111d1d95fcbSLiam Girdwood 	change = snd_sof_dsp_update_bits64_unlocked(sdev, bar, offset, mask,
112d1d95fcbSLiam Girdwood 						    value);
113d1d95fcbSLiam Girdwood 	spin_unlock_irqrestore(&sdev->hw_lock, flags);
114d1d95fcbSLiam Girdwood 	return change;
115d1d95fcbSLiam Girdwood }
116d1d95fcbSLiam Girdwood EXPORT_SYMBOL(snd_sof_dsp_update_bits64);
117d1d95fcbSLiam Girdwood 
118d1d95fcbSLiam Girdwood static
snd_sof_dsp_update_bits_forced_unlocked(struct snd_sof_dev * sdev,u32 bar,u32 offset,u32 mask,u32 value)119d1d95fcbSLiam Girdwood void snd_sof_dsp_update_bits_forced_unlocked(struct snd_sof_dev *sdev, u32 bar,
120d1d95fcbSLiam Girdwood 					     u32 offset, u32 mask, u32 value)
121d1d95fcbSLiam Girdwood {
122d1d95fcbSLiam Girdwood 	unsigned int old, new;
123d1d95fcbSLiam Girdwood 	u32 ret;
124d1d95fcbSLiam Girdwood 
125d1d95fcbSLiam Girdwood 	ret = snd_sof_dsp_read(sdev, bar, offset);
126d1d95fcbSLiam Girdwood 
127d1d95fcbSLiam Girdwood 	old = ret;
128d1d95fcbSLiam Girdwood 	new = (old & ~mask) | (value & mask);
129d1d95fcbSLiam Girdwood 
130d1d95fcbSLiam Girdwood 	snd_sof_dsp_write(sdev, bar, offset, new);
131d1d95fcbSLiam Girdwood }
132d1d95fcbSLiam Girdwood 
133d1d95fcbSLiam Girdwood /* This is for registers bits with attribute RWC */
snd_sof_dsp_update_bits_forced(struct snd_sof_dev * sdev,u32 bar,u32 offset,u32 mask,u32 value)134d1d95fcbSLiam Girdwood void snd_sof_dsp_update_bits_forced(struct snd_sof_dev *sdev, u32 bar,
135d1d95fcbSLiam Girdwood 				    u32 offset, u32 mask, u32 value)
136d1d95fcbSLiam Girdwood {
137d1d95fcbSLiam Girdwood 	unsigned long flags;
138d1d95fcbSLiam Girdwood 
139d1d95fcbSLiam Girdwood 	spin_lock_irqsave(&sdev->hw_lock, flags);
140d1d95fcbSLiam Girdwood 	snd_sof_dsp_update_bits_forced_unlocked(sdev, bar, offset, mask, value);
141d1d95fcbSLiam Girdwood 	spin_unlock_irqrestore(&sdev->hw_lock, flags);
142d1d95fcbSLiam Girdwood }
143d1d95fcbSLiam Girdwood EXPORT_SYMBOL(snd_sof_dsp_update_bits_forced);
144d1d95fcbSLiam Girdwood 
145b2b10aa7SPeter Ujfalusi /**
146b2b10aa7SPeter Ujfalusi  * snd_sof_dsp_panic - handle a received DSP panic message
147b2b10aa7SPeter Ujfalusi  * @sdev: Pointer to the device's sdev
148b2b10aa7SPeter Ujfalusi  * @offset: offset of panic information
149b2b10aa7SPeter Ujfalusi  * @non_recoverable: the panic is fatal, no recovery will be done by the caller
150b2b10aa7SPeter Ujfalusi  */
snd_sof_dsp_panic(struct snd_sof_dev * sdev,u32 offset,bool non_recoverable)151b2b10aa7SPeter Ujfalusi void snd_sof_dsp_panic(struct snd_sof_dev *sdev, u32 offset, bool non_recoverable)
152d1d95fcbSLiam Girdwood {
153d1d95fcbSLiam Girdwood 	/*
15472b8ed83SPeter Ujfalusi 	 * if DSP is not ready and the dsp_oops_offset is not yet set, use the
15572b8ed83SPeter Ujfalusi 	 * offset from the panic message.
156d1d95fcbSLiam Girdwood 	 */
157d1d95fcbSLiam Girdwood 	if (!sdev->dsp_oops_offset)
158d1d95fcbSLiam Girdwood 		sdev->dsp_oops_offset = offset;
15972b8ed83SPeter Ujfalusi 
16072b8ed83SPeter Ujfalusi 	/*
16172b8ed83SPeter Ujfalusi 	 * Print warning if the offset from the panic message differs from
16272b8ed83SPeter Ujfalusi 	 * dsp_oops_offset
16372b8ed83SPeter Ujfalusi 	 */
16472b8ed83SPeter Ujfalusi 	if (sdev->dsp_oops_offset != offset)
16572b8ed83SPeter Ujfalusi 		dev_warn(sdev->dev,
16672b8ed83SPeter Ujfalusi 			 "%s: dsp_oops_offset %zu differs from panic offset %u\n",
16772b8ed83SPeter Ujfalusi 			 __func__, sdev->dsp_oops_offset, offset);
16872b8ed83SPeter Ujfalusi 
169b2b10aa7SPeter Ujfalusi 	/*
170fdc573b1SPeter Ujfalusi 	 * Set the fw_state to crashed only in case of non recoverable DSP panic
171fdc573b1SPeter Ujfalusi 	 * event.
172fdc573b1SPeter Ujfalusi 	 * Use different message within the snd_sof_dsp_dbg_dump() depending on
173fdc573b1SPeter Ujfalusi 	 * the non_recoverable flag.
174b2b10aa7SPeter Ujfalusi 	 */
175705f4539SPeter Ujfalusi 	sdev->dbg_dump_printed = false;
176fdc573b1SPeter Ujfalusi 	if (non_recoverable) {
1772f148430SPeter Ujfalusi 		snd_sof_dsp_dbg_dump(sdev, "DSP panic!",
1782f148430SPeter Ujfalusi 				     SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX);
1794e1f8648SPeter Ujfalusi 		sof_set_fw_state(sdev, SOF_FW_CRASHED);
180*1dedbe4fSPeter Ujfalusi 		sof_fw_trace_fw_crashed(sdev);
181fdc573b1SPeter Ujfalusi 	} else {
182fdc573b1SPeter Ujfalusi 		snd_sof_dsp_dbg_dump(sdev,
183fdc573b1SPeter Ujfalusi 				     "DSP panic (recovery will be attempted)",
184fdc573b1SPeter Ujfalusi 				     SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX);
185d1d95fcbSLiam Girdwood 	}
186b2b10aa7SPeter Ujfalusi }
187d1d95fcbSLiam Girdwood EXPORT_SYMBOL(snd_sof_dsp_panic);
188