18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * PeeCeeI.c: The emerging standard...
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/module.h>
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <asm/io.h>
118c2ecf20Sopenharmony_ci#include <asm/byteorder.h>
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_civoid outsb(unsigned long __addr, const void *src, unsigned long count)
148c2ecf20Sopenharmony_ci{
158c2ecf20Sopenharmony_ci	void __iomem *addr = (void __iomem *) __addr;
168c2ecf20Sopenharmony_ci	const u8 *p = src;
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci	while (count--)
198c2ecf20Sopenharmony_ci		__raw_writeb(*p++, addr);
208c2ecf20Sopenharmony_ci}
218c2ecf20Sopenharmony_ciEXPORT_SYMBOL(outsb);
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_civoid outsw(unsigned long __addr, const void *src, unsigned long count)
248c2ecf20Sopenharmony_ci{
258c2ecf20Sopenharmony_ci	void __iomem *addr = (void __iomem *) __addr;
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci	while (count--) {
288c2ecf20Sopenharmony_ci		__raw_writew(*(u16 *)src, addr);
298c2ecf20Sopenharmony_ci		src += sizeof(u16);
308c2ecf20Sopenharmony_ci	}
318c2ecf20Sopenharmony_ci}
328c2ecf20Sopenharmony_ciEXPORT_SYMBOL(outsw);
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_civoid outsl(unsigned long __addr, const void *src, unsigned long count)
358c2ecf20Sopenharmony_ci{
368c2ecf20Sopenharmony_ci	void __iomem *addr = (void __iomem *) __addr;
378c2ecf20Sopenharmony_ci	u32 l, l2;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	if (!count)
408c2ecf20Sopenharmony_ci		return;
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	switch (((unsigned long)src) & 0x3) {
438c2ecf20Sopenharmony_ci	case 0x0:
448c2ecf20Sopenharmony_ci		/* src is naturally aligned */
458c2ecf20Sopenharmony_ci		while (count--) {
468c2ecf20Sopenharmony_ci			__raw_writel(*(u32 *)src, addr);
478c2ecf20Sopenharmony_ci			src += sizeof(u32);
488c2ecf20Sopenharmony_ci		}
498c2ecf20Sopenharmony_ci		break;
508c2ecf20Sopenharmony_ci	case 0x2:
518c2ecf20Sopenharmony_ci		/* 2-byte alignment */
528c2ecf20Sopenharmony_ci		while (count--) {
538c2ecf20Sopenharmony_ci			l = (*(u16 *)src) << 16;
548c2ecf20Sopenharmony_ci			l |= *(u16 *)(src + sizeof(u16));
558c2ecf20Sopenharmony_ci			__raw_writel(l, addr);
568c2ecf20Sopenharmony_ci			src += sizeof(u32);
578c2ecf20Sopenharmony_ci		}
588c2ecf20Sopenharmony_ci		break;
598c2ecf20Sopenharmony_ci	case 0x1:
608c2ecf20Sopenharmony_ci		/* Hold three bytes in l each time, grab a byte from l2 */
618c2ecf20Sopenharmony_ci		l = (*(u8 *)src) << 24;
628c2ecf20Sopenharmony_ci		l |= (*(u16 *)(src + sizeof(u8))) << 8;
638c2ecf20Sopenharmony_ci		src += sizeof(u8) + sizeof(u16);
648c2ecf20Sopenharmony_ci		while (count--) {
658c2ecf20Sopenharmony_ci			l2 = *(u32 *)src;
668c2ecf20Sopenharmony_ci			l |= (l2 >> 24);
678c2ecf20Sopenharmony_ci			__raw_writel(l, addr);
688c2ecf20Sopenharmony_ci			l = l2 << 8;
698c2ecf20Sopenharmony_ci			src += sizeof(u32);
708c2ecf20Sopenharmony_ci		}
718c2ecf20Sopenharmony_ci		break;
728c2ecf20Sopenharmony_ci	case 0x3:
738c2ecf20Sopenharmony_ci		/* Hold a byte in l each time, grab 3 bytes from l2 */
748c2ecf20Sopenharmony_ci		l = (*(u8 *)src) << 24;
758c2ecf20Sopenharmony_ci		src += sizeof(u8);
768c2ecf20Sopenharmony_ci		while (count--) {
778c2ecf20Sopenharmony_ci			l2 = *(u32 *)src;
788c2ecf20Sopenharmony_ci			l |= (l2 >> 8);
798c2ecf20Sopenharmony_ci			__raw_writel(l, addr);
808c2ecf20Sopenharmony_ci			l = l2 << 24;
818c2ecf20Sopenharmony_ci			src += sizeof(u32);
828c2ecf20Sopenharmony_ci		}
838c2ecf20Sopenharmony_ci		break;
848c2ecf20Sopenharmony_ci	}
858c2ecf20Sopenharmony_ci}
868c2ecf20Sopenharmony_ciEXPORT_SYMBOL(outsl);
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_civoid insb(unsigned long __addr, void *dst, unsigned long count)
898c2ecf20Sopenharmony_ci{
908c2ecf20Sopenharmony_ci	void __iomem *addr = (void __iomem *) __addr;
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	if (count) {
938c2ecf20Sopenharmony_ci		u32 *pi;
948c2ecf20Sopenharmony_ci		u8 *pb = dst;
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci		while ((((unsigned long)pb) & 0x3) && count--)
978c2ecf20Sopenharmony_ci			*pb++ = __raw_readb(addr);
988c2ecf20Sopenharmony_ci		pi = (u32 *)pb;
998c2ecf20Sopenharmony_ci		while (count >= 4) {
1008c2ecf20Sopenharmony_ci			u32 w;
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci			w  = (__raw_readb(addr) << 24);
1038c2ecf20Sopenharmony_ci			w |= (__raw_readb(addr) << 16);
1048c2ecf20Sopenharmony_ci			w |= (__raw_readb(addr) << 8);
1058c2ecf20Sopenharmony_ci			w |= (__raw_readb(addr) << 0);
1068c2ecf20Sopenharmony_ci			*pi++ = w;
1078c2ecf20Sopenharmony_ci			count -= 4;
1088c2ecf20Sopenharmony_ci		}
1098c2ecf20Sopenharmony_ci		pb = (u8 *)pi;
1108c2ecf20Sopenharmony_ci		while (count--)
1118c2ecf20Sopenharmony_ci			*pb++ = __raw_readb(addr);
1128c2ecf20Sopenharmony_ci	}
1138c2ecf20Sopenharmony_ci}
1148c2ecf20Sopenharmony_ciEXPORT_SYMBOL(insb);
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_civoid insw(unsigned long __addr, void *dst, unsigned long count)
1178c2ecf20Sopenharmony_ci{
1188c2ecf20Sopenharmony_ci	void __iomem *addr = (void __iomem *) __addr;
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	if (count) {
1218c2ecf20Sopenharmony_ci		u16 *ps = dst;
1228c2ecf20Sopenharmony_ci		u32 *pi;
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci		if (((unsigned long)ps) & 0x2) {
1258c2ecf20Sopenharmony_ci			*ps++ = __raw_readw(addr);
1268c2ecf20Sopenharmony_ci			count--;
1278c2ecf20Sopenharmony_ci		}
1288c2ecf20Sopenharmony_ci		pi = (u32 *)ps;
1298c2ecf20Sopenharmony_ci		while (count >= 2) {
1308c2ecf20Sopenharmony_ci			u32 w;
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci			w  = __raw_readw(addr) << 16;
1338c2ecf20Sopenharmony_ci			w |= __raw_readw(addr) << 0;
1348c2ecf20Sopenharmony_ci			*pi++ = w;
1358c2ecf20Sopenharmony_ci			count -= 2;
1368c2ecf20Sopenharmony_ci		}
1378c2ecf20Sopenharmony_ci		ps = (u16 *)pi;
1388c2ecf20Sopenharmony_ci		if (count)
1398c2ecf20Sopenharmony_ci			*ps = __raw_readw(addr);
1408c2ecf20Sopenharmony_ci	}
1418c2ecf20Sopenharmony_ci}
1428c2ecf20Sopenharmony_ciEXPORT_SYMBOL(insw);
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_civoid insl(unsigned long __addr, void *dst, unsigned long count)
1458c2ecf20Sopenharmony_ci{
1468c2ecf20Sopenharmony_ci	void __iomem *addr = (void __iomem *) __addr;
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	if (count) {
1498c2ecf20Sopenharmony_ci		if ((((unsigned long)dst) & 0x3) == 0) {
1508c2ecf20Sopenharmony_ci			u32 *pi = dst;
1518c2ecf20Sopenharmony_ci			while (count--)
1528c2ecf20Sopenharmony_ci				*pi++ = __raw_readl(addr);
1538c2ecf20Sopenharmony_ci		} else {
1548c2ecf20Sopenharmony_ci			u32 l = 0, l2, *pi;
1558c2ecf20Sopenharmony_ci			u16 *ps;
1568c2ecf20Sopenharmony_ci			u8 *pb;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci			switch (((unsigned long)dst) & 3) {
1598c2ecf20Sopenharmony_ci			case 0x2:
1608c2ecf20Sopenharmony_ci				ps = dst;
1618c2ecf20Sopenharmony_ci				count -= 1;
1628c2ecf20Sopenharmony_ci				l = __raw_readl(addr);
1638c2ecf20Sopenharmony_ci				*ps++ = l;
1648c2ecf20Sopenharmony_ci				pi = (u32 *)ps;
1658c2ecf20Sopenharmony_ci				while (count--) {
1668c2ecf20Sopenharmony_ci					l2 = __raw_readl(addr);
1678c2ecf20Sopenharmony_ci					*pi++ = (l << 16) | (l2 >> 16);
1688c2ecf20Sopenharmony_ci					l = l2;
1698c2ecf20Sopenharmony_ci				}
1708c2ecf20Sopenharmony_ci				ps = (u16 *)pi;
1718c2ecf20Sopenharmony_ci				*ps = l;
1728c2ecf20Sopenharmony_ci				break;
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci			case 0x1:
1758c2ecf20Sopenharmony_ci				pb = dst;
1768c2ecf20Sopenharmony_ci				count -= 1;
1778c2ecf20Sopenharmony_ci				l = __raw_readl(addr);
1788c2ecf20Sopenharmony_ci				*pb++ = l >> 24;
1798c2ecf20Sopenharmony_ci				ps = (u16 *)pb;
1808c2ecf20Sopenharmony_ci				*ps++ = ((l >> 8) & 0xffff);
1818c2ecf20Sopenharmony_ci				pi = (u32 *)ps;
1828c2ecf20Sopenharmony_ci				while (count--) {
1838c2ecf20Sopenharmony_ci					l2 = __raw_readl(addr);
1848c2ecf20Sopenharmony_ci					*pi++ = (l << 24) | (l2 >> 8);
1858c2ecf20Sopenharmony_ci					l = l2;
1868c2ecf20Sopenharmony_ci				}
1878c2ecf20Sopenharmony_ci				pb = (u8 *)pi;
1888c2ecf20Sopenharmony_ci				*pb = l;
1898c2ecf20Sopenharmony_ci				break;
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci			case 0x3:
1928c2ecf20Sopenharmony_ci				pb = (u8 *)dst;
1938c2ecf20Sopenharmony_ci				count -= 1;
1948c2ecf20Sopenharmony_ci				l = __raw_readl(addr);
1958c2ecf20Sopenharmony_ci				*pb++ = l >> 24;
1968c2ecf20Sopenharmony_ci				pi = (u32 *)pb;
1978c2ecf20Sopenharmony_ci				while (count--) {
1988c2ecf20Sopenharmony_ci					l2 = __raw_readl(addr);
1998c2ecf20Sopenharmony_ci					*pi++ = (l << 8) | (l2 >> 24);
2008c2ecf20Sopenharmony_ci					l = l2;
2018c2ecf20Sopenharmony_ci				}
2028c2ecf20Sopenharmony_ci				ps = (u16 *)pi;
2038c2ecf20Sopenharmony_ci				*ps++ = ((l >> 8) & 0xffff);
2048c2ecf20Sopenharmony_ci				pb = (u8 *)ps;
2058c2ecf20Sopenharmony_ci				*pb = l;
2068c2ecf20Sopenharmony_ci				break;
2078c2ecf20Sopenharmony_ci			}
2088c2ecf20Sopenharmony_ci		}
2098c2ecf20Sopenharmony_ci	}
2108c2ecf20Sopenharmony_ci}
2118c2ecf20Sopenharmony_ciEXPORT_SYMBOL(insl);
2128c2ecf20Sopenharmony_ci
213