1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
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.
6 // Copyright(c) 2018 Intel Corporation. All rights reserved.
8 // Author: Keyon Jie <yang.jie@linux.intel.com>
11 #include <linux/io-64-nonatomic-lo-hi.h>
12 #include <linux/platform_device.h>
13 #include <asm/unaligned.h>
14 #include <sound/soc.h>
15 #include <sound/sof.h>
21 * The sof_io_xyz() wrappers are typically referenced in snd_sof_dsp_ops
22 * structures and cannot be inlined.
25 void sof_io_write(struct snd_sof_dev
*sdev
, void __iomem
*addr
, u32 value
)
29 EXPORT_SYMBOL(sof_io_write
);
31 u32
sof_io_read(struct snd_sof_dev
*sdev
, void __iomem
*addr
)
35 EXPORT_SYMBOL(sof_io_read
);
37 void sof_io_write64(struct snd_sof_dev
*sdev
, void __iomem
*addr
, u64 value
)
41 EXPORT_SYMBOL(sof_io_write64
);
43 u64
sof_io_read64(struct snd_sof_dev
*sdev
, void __iomem
*addr
)
47 EXPORT_SYMBOL(sof_io_read64
);
53 void sof_mailbox_write(struct snd_sof_dev
*sdev
, u32 offset
,
54 void *message
, size_t bytes
)
56 void __iomem
*dest
= sdev
->bar
[sdev
->mailbox_bar
] + offset
;
58 memcpy_toio(dest
, message
, bytes
);
60 EXPORT_SYMBOL(sof_mailbox_write
);
62 void sof_mailbox_read(struct snd_sof_dev
*sdev
, u32 offset
,
63 void *message
, size_t bytes
)
65 void __iomem
*src
= sdev
->bar
[sdev
->mailbox_bar
] + offset
;
67 memcpy_fromio(message
, src
, bytes
);
69 EXPORT_SYMBOL(sof_mailbox_read
);
75 void sof_block_write(struct snd_sof_dev
*sdev
, u32 bar
, u32 offset
, void *src
,
78 void __iomem
*dest
= sdev
->bar
[bar
] + offset
;
79 const u8
*src_byte
= src
;
87 /* __iowrite32_copy use 32bit size values so divide by 4 */
88 __iowrite32_copy(dest
, src
, m
);
91 affected_mask
= (1 << (8 * n
)) - 1;
93 /* first read the 32bit data of dest, then change affected
94 * bytes, and write back to dest. For unaffected bytes, it
95 * should not be changed
97 tmp
= ioread32(dest
+ m
* 4);
98 tmp
&= ~affected_mask
;
100 tmp
|= *(u32
*)(src_byte
+ m
* 4) & affected_mask
;
101 iowrite32(tmp
, dest
+ m
* 4);
104 EXPORT_SYMBOL(sof_block_write
);
106 void sof_block_read(struct snd_sof_dev
*sdev
, u32 bar
, u32 offset
, void *dest
,
109 void __iomem
*src
= sdev
->bar
[bar
] + offset
;
111 memcpy_fromio(dest
, src
, size
);
113 EXPORT_SYMBOL(sof_block_read
);
116 * Generic buffer page table creation.
117 * Take the each physical page address and drop the least significant unused
118 * bits from each (based on PAGE_SIZE). Then pack valid page address bits
119 * into compressed page table.
122 int snd_sof_create_page_table(struct device
*dev
,
123 struct snd_dma_buffer
*dmab
,
124 unsigned char *page_table
, size_t size
)
128 pages
= snd_sgbuf_aligned_pages(size
);
130 dev_dbg(dev
, "generating page table for %p size 0x%zx pages %d\n",
131 dmab
->area
, size
, pages
);
133 for (i
= 0; i
< pages
; i
++) {
135 * The number of valid address bits for each page is 20.
136 * idx determines the byte position within page_table
137 * where the current page's address is stored
138 * in the compressed page_table.
139 * This can be calculated by multiplying the page number by 2.5.
141 u32 idx
= (5 * i
) >> 1;
142 u32 pfn
= snd_sgbuf_get_addr(dmab
, i
* PAGE_SIZE
) >> PAGE_SHIFT
;
145 dev_vdbg(dev
, "pfn i %i idx %d pfn %x\n", i
, idx
, pfn
);
147 pg_table
= (u8
*)(page_table
+ idx
);
150 * pagetable compression:
151 * byte 0 byte 1 byte 2 byte 3 byte 4 byte 5
152 * ___________pfn 0__________ __________pfn 1___________ _pfn 2...
153 * .... .... .... .... .... .... .... .... .... .... ....
155 * 1. set current location to 0, PFN index i to 0
156 * 2. put pfn[i] at current location in Little Endian byte order
157 * 3. calculate an intermediate value as
158 * x = (pfn[i+1] << 4) | (pfn[i] & 0xf)
159 * 4. put x at offset (current location + 2) in LE byte order
160 * 5. increment current location by 5 bytes, increment i by 2
164 put_unaligned_le32((pg_table
[0] & 0xf) | pfn
<< 4,
167 put_unaligned_le32(pfn
, pg_table
);
172 EXPORT_SYMBOL(snd_sof_create_page_table
);