1// SPDX-License-Identifier: GPL-2.0
2/*
3 * PeeCeeI.c: The emerging standard...
4 *
5 * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
6 */
7
8#include <linux/module.h>
9
10#include <asm/io.h>
11#include <asm/byteorder.h>
12
13void outsb(unsigned long __addr, const void *src, unsigned long count)
14{
15	void __iomem *addr = (void __iomem *) __addr;
16	const u8 *p = src;
17
18	while (count--)
19		__raw_writeb(*p++, addr);
20}
21EXPORT_SYMBOL(outsb);
22
23void outsw(unsigned long __addr, const void *src, unsigned long count)
24{
25	void __iomem *addr = (void __iomem *) __addr;
26
27	while (count--) {
28		__raw_writew(*(u16 *)src, addr);
29		src += sizeof(u16);
30	}
31}
32EXPORT_SYMBOL(outsw);
33
34void outsl(unsigned long __addr, const void *src, unsigned long count)
35{
36	void __iomem *addr = (void __iomem *) __addr;
37	u32 l, l2;
38
39	if (!count)
40		return;
41
42	switch (((unsigned long)src) & 0x3) {
43	case 0x0:
44		/* src is naturally aligned */
45		while (count--) {
46			__raw_writel(*(u32 *)src, addr);
47			src += sizeof(u32);
48		}
49		break;
50	case 0x2:
51		/* 2-byte alignment */
52		while (count--) {
53			l = (*(u16 *)src) << 16;
54			l |= *(u16 *)(src + sizeof(u16));
55			__raw_writel(l, addr);
56			src += sizeof(u32);
57		}
58		break;
59	case 0x1:
60		/* Hold three bytes in l each time, grab a byte from l2 */
61		l = (*(u8 *)src) << 24;
62		l |= (*(u16 *)(src + sizeof(u8))) << 8;
63		src += sizeof(u8) + sizeof(u16);
64		while (count--) {
65			l2 = *(u32 *)src;
66			l |= (l2 >> 24);
67			__raw_writel(l, addr);
68			l = l2 << 8;
69			src += sizeof(u32);
70		}
71		break;
72	case 0x3:
73		/* Hold a byte in l each time, grab 3 bytes from l2 */
74		l = (*(u8 *)src) << 24;
75		src += sizeof(u8);
76		while (count--) {
77			l2 = *(u32 *)src;
78			l |= (l2 >> 8);
79			__raw_writel(l, addr);
80			l = l2 << 24;
81			src += sizeof(u32);
82		}
83		break;
84	}
85}
86EXPORT_SYMBOL(outsl);
87
88void insb(unsigned long __addr, void *dst, unsigned long count)
89{
90	void __iomem *addr = (void __iomem *) __addr;
91
92	if (count) {
93		u32 *pi;
94		u8 *pb = dst;
95
96		while ((((unsigned long)pb) & 0x3) && count--)
97			*pb++ = __raw_readb(addr);
98		pi = (u32 *)pb;
99		while (count >= 4) {
100			u32 w;
101
102			w  = (__raw_readb(addr) << 24);
103			w |= (__raw_readb(addr) << 16);
104			w |= (__raw_readb(addr) << 8);
105			w |= (__raw_readb(addr) << 0);
106			*pi++ = w;
107			count -= 4;
108		}
109		pb = (u8 *)pi;
110		while (count--)
111			*pb++ = __raw_readb(addr);
112	}
113}
114EXPORT_SYMBOL(insb);
115
116void insw(unsigned long __addr, void *dst, unsigned long count)
117{
118	void __iomem *addr = (void __iomem *) __addr;
119
120	if (count) {
121		u16 *ps = dst;
122		u32 *pi;
123
124		if (((unsigned long)ps) & 0x2) {
125			*ps++ = __raw_readw(addr);
126			count--;
127		}
128		pi = (u32 *)ps;
129		while (count >= 2) {
130			u32 w;
131
132			w  = __raw_readw(addr) << 16;
133			w |= __raw_readw(addr) << 0;
134			*pi++ = w;
135			count -= 2;
136		}
137		ps = (u16 *)pi;
138		if (count)
139			*ps = __raw_readw(addr);
140	}
141}
142EXPORT_SYMBOL(insw);
143
144void insl(unsigned long __addr, void *dst, unsigned long count)
145{
146	void __iomem *addr = (void __iomem *) __addr;
147
148	if (count) {
149		if ((((unsigned long)dst) & 0x3) == 0) {
150			u32 *pi = dst;
151			while (count--)
152				*pi++ = __raw_readl(addr);
153		} else {
154			u32 l = 0, l2, *pi;
155			u16 *ps;
156			u8 *pb;
157
158			switch (((unsigned long)dst) & 3) {
159			case 0x2:
160				ps = dst;
161				count -= 1;
162				l = __raw_readl(addr);
163				*ps++ = l;
164				pi = (u32 *)ps;
165				while (count--) {
166					l2 = __raw_readl(addr);
167					*pi++ = (l << 16) | (l2 >> 16);
168					l = l2;
169				}
170				ps = (u16 *)pi;
171				*ps = l;
172				break;
173
174			case 0x1:
175				pb = dst;
176				count -= 1;
177				l = __raw_readl(addr);
178				*pb++ = l >> 24;
179				ps = (u16 *)pb;
180				*ps++ = ((l >> 8) & 0xffff);
181				pi = (u32 *)ps;
182				while (count--) {
183					l2 = __raw_readl(addr);
184					*pi++ = (l << 24) | (l2 >> 8);
185					l = l2;
186				}
187				pb = (u8 *)pi;
188				*pb = l;
189				break;
190
191			case 0x3:
192				pb = (u8 *)dst;
193				count -= 1;
194				l = __raw_readl(addr);
195				*pb++ = l >> 24;
196				pi = (u32 *)pb;
197				while (count--) {
198					l2 = __raw_readl(addr);
199					*pi++ = (l << 8) | (l2 >> 24);
200					l = l2;
201				}
202				ps = (u16 *)pi;
203				*ps++ = ((l >> 8) & 0xffff);
204				pb = (u8 *)ps;
205				*pb = l;
206				break;
207			}
208		}
209	}
210}
211EXPORT_SYMBOL(insl);
212
213