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