linux/sound/soc/sof/ops.c
<<
>>
Prefs
   1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
   2//
   3// This file is provided under a dual BSD/GPLv2 license.  When using or
   4// redistributing this file, you may do so under either license.
   5//
   6// Copyright(c) 2018 Intel Corporation. All rights reserved.
   7//
   8// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
   9//
  10
  11#include <linux/pci.h>
  12#include "ops.h"
  13
  14static
  15bool snd_sof_pci_update_bits_unlocked(struct snd_sof_dev *sdev, u32 offset,
  16                                      u32 mask, u32 value)
  17{
  18        struct pci_dev *pci = to_pci_dev(sdev->dev);
  19        unsigned int old, new;
  20        u32 ret = 0;
  21
  22        pci_read_config_dword(pci, offset, &ret);
  23        old = ret;
  24        dev_dbg(sdev->dev, "Debug PCIR: %8.8x at  %8.8x\n", old & mask, offset);
  25
  26        new = (old & ~mask) | (value & mask);
  27
  28        if (old == new)
  29                return false;
  30
  31        pci_write_config_dword(pci, offset, new);
  32        dev_dbg(sdev->dev, "Debug PCIW: %8.8x at  %8.8x\n", value,
  33                offset);
  34
  35        return true;
  36}
  37
  38bool snd_sof_pci_update_bits(struct snd_sof_dev *sdev, u32 offset,
  39                             u32 mask, u32 value)
  40{
  41        unsigned long flags;
  42        bool change;
  43
  44        spin_lock_irqsave(&sdev->hw_lock, flags);
  45        change = snd_sof_pci_update_bits_unlocked(sdev, offset, mask, value);
  46        spin_unlock_irqrestore(&sdev->hw_lock, flags);
  47        return change;
  48}
  49EXPORT_SYMBOL(snd_sof_pci_update_bits);
  50
  51bool snd_sof_dsp_update_bits_unlocked(struct snd_sof_dev *sdev, u32 bar,
  52                                      u32 offset, u32 mask, u32 value)
  53{
  54        unsigned int old, new;
  55        u32 ret;
  56
  57        ret = snd_sof_dsp_read(sdev, bar, offset);
  58
  59        old = ret;
  60        new = (old & ~mask) | (value & mask);
  61
  62        if (old == new)
  63                return false;
  64
  65        snd_sof_dsp_write(sdev, bar, offset, new);
  66
  67        return true;
  68}
  69EXPORT_SYMBOL(snd_sof_dsp_update_bits_unlocked);
  70
  71bool snd_sof_dsp_update_bits64_unlocked(struct snd_sof_dev *sdev, u32 bar,
  72                                        u32 offset, u64 mask, u64 value)
  73{
  74        u64 old, new;
  75
  76        old = snd_sof_dsp_read64(sdev, bar, offset);
  77
  78        new = (old & ~mask) | (value & mask);
  79
  80        if (old == new)
  81                return false;
  82
  83        snd_sof_dsp_write64(sdev, bar, offset, new);
  84
  85        return true;
  86}
  87EXPORT_SYMBOL(snd_sof_dsp_update_bits64_unlocked);
  88
  89/* This is for registers bits with attribute RWC */
  90bool snd_sof_dsp_update_bits(struct snd_sof_dev *sdev, u32 bar, u32 offset,
  91                             u32 mask, u32 value)
  92{
  93        unsigned long flags;
  94        bool change;
  95
  96        spin_lock_irqsave(&sdev->hw_lock, flags);
  97        change = snd_sof_dsp_update_bits_unlocked(sdev, bar, offset, mask,
  98                                                  value);
  99        spin_unlock_irqrestore(&sdev->hw_lock, flags);
 100        return change;
 101}
 102EXPORT_SYMBOL(snd_sof_dsp_update_bits);
 103
 104bool snd_sof_dsp_update_bits64(struct snd_sof_dev *sdev, u32 bar, u32 offset,
 105                               u64 mask, u64 value)
 106{
 107        unsigned long flags;
 108        bool change;
 109
 110        spin_lock_irqsave(&sdev->hw_lock, flags);
 111        change = snd_sof_dsp_update_bits64_unlocked(sdev, bar, offset, mask,
 112                                                    value);
 113        spin_unlock_irqrestore(&sdev->hw_lock, flags);
 114        return change;
 115}
 116EXPORT_SYMBOL(snd_sof_dsp_update_bits64);
 117
 118static
 119void snd_sof_dsp_update_bits_forced_unlocked(struct snd_sof_dev *sdev, u32 bar,
 120                                             u32 offset, u32 mask, u32 value)
 121{
 122        unsigned int old, new;
 123        u32 ret;
 124
 125        ret = snd_sof_dsp_read(sdev, bar, offset);
 126
 127        old = ret;
 128        new = (old & ~mask) | (value & mask);
 129
 130        snd_sof_dsp_write(sdev, bar, offset, new);
 131}
 132
 133/* This is for registers bits with attribute RWC */
 134void snd_sof_dsp_update_bits_forced(struct snd_sof_dev *sdev, u32 bar,
 135                                    u32 offset, u32 mask, u32 value)
 136{
 137        unsigned long flags;
 138
 139        spin_lock_irqsave(&sdev->hw_lock, flags);
 140        snd_sof_dsp_update_bits_forced_unlocked(sdev, bar, offset, mask, value);
 141        spin_unlock_irqrestore(&sdev->hw_lock, flags);
 142}
 143EXPORT_SYMBOL(snd_sof_dsp_update_bits_forced);
 144
 145void snd_sof_dsp_panic(struct snd_sof_dev *sdev, u32 offset)
 146{
 147        dev_err(sdev->dev, "error : DSP panic!\n");
 148
 149        /*
 150         * check if DSP is not ready and did not set the dsp_oops_offset.
 151         * if the dsp_oops_offset is not set, set it from the panic message.
 152         * Also add a check to memory window setting with panic message.
 153         */
 154        if (!sdev->dsp_oops_offset)
 155                sdev->dsp_oops_offset = offset;
 156        else
 157                dev_dbg(sdev->dev, "panic: dsp_oops_offset %zu offset %d\n",
 158                        sdev->dsp_oops_offset, offset);
 159
 160        snd_sof_dsp_dbg_dump(sdev, SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX);
 161        snd_sof_trace_notify_for_error(sdev);
 162}
 163EXPORT_SYMBOL(snd_sof_dsp_panic);
 164