162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) 262306a36Sopenharmony_ci// 362306a36Sopenharmony_ci// This file is provided under a dual BSD/GPLv2 license. When using or 462306a36Sopenharmony_ci// redistributing this file, you may do so under either license. 562306a36Sopenharmony_ci// 662306a36Sopenharmony_ci// Copyright(c) 2018-2022 Intel Corporation. All rights reserved. 762306a36Sopenharmony_ci// 862306a36Sopenharmony_ci// Author: Keyon Jie <yang.jie@linux.intel.com> 962306a36Sopenharmony_ci// 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/io-64-nonatomic-lo-hi.h> 1262306a36Sopenharmony_ci#include <linux/platform_device.h> 1362306a36Sopenharmony_ci#include <asm/unaligned.h> 1462306a36Sopenharmony_ci#include <sound/soc.h> 1562306a36Sopenharmony_ci#include <sound/sof.h> 1662306a36Sopenharmony_ci#include "sof-priv.h" 1762306a36Sopenharmony_ci#include "ops.h" 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci/* 2062306a36Sopenharmony_ci * Register IO 2162306a36Sopenharmony_ci * 2262306a36Sopenharmony_ci * The sof_io_xyz() wrappers are typically referenced in snd_sof_dsp_ops 2362306a36Sopenharmony_ci * structures and cannot be inlined. 2462306a36Sopenharmony_ci */ 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_civoid sof_io_write(struct snd_sof_dev *sdev, void __iomem *addr, u32 value) 2762306a36Sopenharmony_ci{ 2862306a36Sopenharmony_ci writel(value, addr); 2962306a36Sopenharmony_ci} 3062306a36Sopenharmony_ciEXPORT_SYMBOL(sof_io_write); 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ciu32 sof_io_read(struct snd_sof_dev *sdev, void __iomem *addr) 3362306a36Sopenharmony_ci{ 3462306a36Sopenharmony_ci return readl(addr); 3562306a36Sopenharmony_ci} 3662306a36Sopenharmony_ciEXPORT_SYMBOL(sof_io_read); 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_civoid sof_io_write64(struct snd_sof_dev *sdev, void __iomem *addr, u64 value) 3962306a36Sopenharmony_ci{ 4062306a36Sopenharmony_ci writeq(value, addr); 4162306a36Sopenharmony_ci} 4262306a36Sopenharmony_ciEXPORT_SYMBOL(sof_io_write64); 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ciu64 sof_io_read64(struct snd_sof_dev *sdev, void __iomem *addr) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci return readq(addr); 4762306a36Sopenharmony_ci} 4862306a36Sopenharmony_ciEXPORT_SYMBOL(sof_io_read64); 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci/* 5162306a36Sopenharmony_ci * IPC Mailbox IO 5262306a36Sopenharmony_ci */ 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_civoid sof_mailbox_write(struct snd_sof_dev *sdev, u32 offset, 5562306a36Sopenharmony_ci void *message, size_t bytes) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci void __iomem *dest = sdev->bar[sdev->mailbox_bar] + offset; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci memcpy_toio(dest, message, bytes); 6062306a36Sopenharmony_ci} 6162306a36Sopenharmony_ciEXPORT_SYMBOL(sof_mailbox_write); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_civoid sof_mailbox_read(struct snd_sof_dev *sdev, u32 offset, 6462306a36Sopenharmony_ci void *message, size_t bytes) 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci void __iomem *src = sdev->bar[sdev->mailbox_bar] + offset; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci memcpy_fromio(message, src, bytes); 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ciEXPORT_SYMBOL(sof_mailbox_read); 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci/* 7362306a36Sopenharmony_ci * Memory copy. 7462306a36Sopenharmony_ci */ 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ciint sof_block_write(struct snd_sof_dev *sdev, enum snd_sof_fw_blk_type blk_type, 7762306a36Sopenharmony_ci u32 offset, void *src, size_t size) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci int bar = snd_sof_dsp_get_bar_index(sdev, blk_type); 8062306a36Sopenharmony_ci const u8 *src_byte = src; 8162306a36Sopenharmony_ci void __iomem *dest; 8262306a36Sopenharmony_ci u32 affected_mask; 8362306a36Sopenharmony_ci u32 tmp; 8462306a36Sopenharmony_ci int m, n; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci if (bar < 0) 8762306a36Sopenharmony_ci return bar; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci dest = sdev->bar[bar] + offset; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci m = size / 4; 9262306a36Sopenharmony_ci n = size % 4; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci /* __iowrite32_copy use 32bit size values so divide by 4 */ 9562306a36Sopenharmony_ci __iowrite32_copy(dest, src, m); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci if (n) { 9862306a36Sopenharmony_ci affected_mask = (1 << (8 * n)) - 1; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci /* first read the 32bit data of dest, then change affected 10162306a36Sopenharmony_ci * bytes, and write back to dest. For unaffected bytes, it 10262306a36Sopenharmony_ci * should not be changed 10362306a36Sopenharmony_ci */ 10462306a36Sopenharmony_ci tmp = ioread32(dest + m * 4); 10562306a36Sopenharmony_ci tmp &= ~affected_mask; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci tmp |= *(u32 *)(src_byte + m * 4) & affected_mask; 10862306a36Sopenharmony_ci iowrite32(tmp, dest + m * 4); 10962306a36Sopenharmony_ci } 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci return 0; 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ciEXPORT_SYMBOL(sof_block_write); 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ciint sof_block_read(struct snd_sof_dev *sdev, enum snd_sof_fw_blk_type blk_type, 11662306a36Sopenharmony_ci u32 offset, void *dest, size_t size) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci int bar = snd_sof_dsp_get_bar_index(sdev, blk_type); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci if (bar < 0) 12162306a36Sopenharmony_ci return bar; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci memcpy_fromio(dest, sdev->bar[bar] + offset, size); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci return 0; 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ciEXPORT_SYMBOL(sof_block_read); 128