^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) #include <linux/export.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include <linux/spinlock.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) static DEFINE_RAW_SPINLOCK(__io_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * Generic atomic MMIO modify.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * Allows thread-safe access to registers shared by unrelated subsystems.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * The access is protected by a single MMIO-wide lock.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) void atomic_io_modify_relaxed(void __iomem *reg, u32 mask, u32 set)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) u32 value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) raw_spin_lock_irqsave(&__io_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) value = readl_relaxed(reg) & ~mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) value |= (set & mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) writel_relaxed(value, reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) raw_spin_unlock_irqrestore(&__io_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) EXPORT_SYMBOL(atomic_io_modify_relaxed);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) void atomic_io_modify(void __iomem *reg, u32 mask, u32 set)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) u32 value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) raw_spin_lock_irqsave(&__io_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) value = readl_relaxed(reg) & ~mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) value |= (set & mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) writel(value, reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) raw_spin_unlock_irqrestore(&__io_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) EXPORT_SYMBOL(atomic_io_modify);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) * Copy data from IO memory space to "real" memory space.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) * This needs to be optimized.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) void _memcpy_fromio(void *to, const volatile void __iomem *from, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) unsigned char *t = to;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) while (count) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) count--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) *t = readb(from);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) t++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) from++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) EXPORT_SYMBOL(_memcpy_fromio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) * Copy data from "real" memory space to IO memory space.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) * This needs to be optimized.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) void _memcpy_toio(volatile void __iomem *to, const void *from, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) const unsigned char *f = from;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) while (count) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) count--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) writeb(*f, to);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) f++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) to++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) EXPORT_SYMBOL(_memcpy_toio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) * "memset" on IO memory space.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) * This needs to be optimized.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) void _memset_io(volatile void __iomem *dst, int c, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) while (count) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) count--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) writeb(c, dst);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) dst++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) EXPORT_SYMBOL(_memset_io);