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