1*4882a593Smuzhiyun /* SPDX-License-Identifier: GPL-2.0-only */ 2*4882a593Smuzhiyun /* 3*4882a593Smuzhiyun * {read,write}{b,w,l,q} based on arch/arm64/include/asm/io.h 4*4882a593Smuzhiyun * which was based on arch/arm/include/io.h 5*4882a593Smuzhiyun * 6*4882a593Smuzhiyun * Copyright (C) 1996-2000 Russell King 7*4882a593Smuzhiyun * Copyright (C) 2012 ARM Ltd. 8*4882a593Smuzhiyun * Copyright (C) 2014 Regents of the University of California 9*4882a593Smuzhiyun */ 10*4882a593Smuzhiyun 11*4882a593Smuzhiyun #ifndef _ASM_RISCV_IO_H 12*4882a593Smuzhiyun #define _ASM_RISCV_IO_H 13*4882a593Smuzhiyun 14*4882a593Smuzhiyun #include <linux/types.h> 15*4882a593Smuzhiyun #include <linux/pgtable.h> 16*4882a593Smuzhiyun #include <asm/mmiowb.h> 17*4882a593Smuzhiyun #include <asm/early_ioremap.h> 18*4882a593Smuzhiyun 19*4882a593Smuzhiyun /* 20*4882a593Smuzhiyun * MMIO access functions are separated out to break dependency cycles 21*4882a593Smuzhiyun * when using {read,write}* fns in low-level headers 22*4882a593Smuzhiyun */ 23*4882a593Smuzhiyun #include <asm/mmio.h> 24*4882a593Smuzhiyun 25*4882a593Smuzhiyun /* 26*4882a593Smuzhiyun * I/O port access constants. 27*4882a593Smuzhiyun */ 28*4882a593Smuzhiyun #ifdef CONFIG_MMU 29*4882a593Smuzhiyun #define IO_SPACE_LIMIT (PCI_IO_SIZE - 1) 30*4882a593Smuzhiyun #define PCI_IOBASE ((void __iomem *)PCI_IO_START) 31*4882a593Smuzhiyun #endif /* CONFIG_MMU */ 32*4882a593Smuzhiyun 33*4882a593Smuzhiyun /* 34*4882a593Smuzhiyun * Emulation routines for the port-mapped IO space used by some PCI drivers. 35*4882a593Smuzhiyun * These are defined as being "fully synchronous", but also "not guaranteed to 36*4882a593Smuzhiyun * be fully ordered with respect to other memory and I/O operations". We're 37*4882a593Smuzhiyun * going to be on the safe side here and just make them: 38*4882a593Smuzhiyun * - Fully ordered WRT each other, by bracketing them with two fences. The 39*4882a593Smuzhiyun * outer set contains both I/O so inX is ordered with outX, while the inner just 40*4882a593Smuzhiyun * needs the type of the access (I for inX and O for outX). 41*4882a593Smuzhiyun * - Ordered in the same manner as readX/writeX WRT memory by subsuming their 42*4882a593Smuzhiyun * fences. 43*4882a593Smuzhiyun * - Ordered WRT timer reads, so udelay and friends don't get elided by the 44*4882a593Smuzhiyun * implementation. 45*4882a593Smuzhiyun * Note that there is no way to actually enforce that outX is a non-posted 46*4882a593Smuzhiyun * operation on RISC-V, but hopefully the timer ordering constraint is 47*4882a593Smuzhiyun * sufficient to ensure this works sanely on controllers that support I/O 48*4882a593Smuzhiyun * writes. 49*4882a593Smuzhiyun */ 50*4882a593Smuzhiyun #define __io_pbr() __asm__ __volatile__ ("fence io,i" : : : "memory"); 51*4882a593Smuzhiyun #define __io_par(v) __asm__ __volatile__ ("fence i,ior" : : : "memory"); 52*4882a593Smuzhiyun #define __io_pbw() __asm__ __volatile__ ("fence iow,o" : : : "memory"); 53*4882a593Smuzhiyun #define __io_paw() __asm__ __volatile__ ("fence o,io" : : : "memory"); 54*4882a593Smuzhiyun 55*4882a593Smuzhiyun #define inb(c) ({ u8 __v; __io_pbr(); __v = readb_cpu((void*)(PCI_IOBASE + (c))); __io_par(__v); __v; }) 56*4882a593Smuzhiyun #define inw(c) ({ u16 __v; __io_pbr(); __v = readw_cpu((void*)(PCI_IOBASE + (c))); __io_par(__v); __v; }) 57*4882a593Smuzhiyun #define inl(c) ({ u32 __v; __io_pbr(); __v = readl_cpu((void*)(PCI_IOBASE + (c))); __io_par(__v); __v; }) 58*4882a593Smuzhiyun 59*4882a593Smuzhiyun #define outb(v,c) ({ __io_pbw(); writeb_cpu((v),(void*)(PCI_IOBASE + (c))); __io_paw(); }) 60*4882a593Smuzhiyun #define outw(v,c) ({ __io_pbw(); writew_cpu((v),(void*)(PCI_IOBASE + (c))); __io_paw(); }) 61*4882a593Smuzhiyun #define outl(v,c) ({ __io_pbw(); writel_cpu((v),(void*)(PCI_IOBASE + (c))); __io_paw(); }) 62*4882a593Smuzhiyun 63*4882a593Smuzhiyun #ifdef CONFIG_64BIT 64*4882a593Smuzhiyun #define inq(c) ({ u64 __v; __io_pbr(); __v = readq_cpu((void*)(c)); __io_par(__v); __v; }) 65*4882a593Smuzhiyun #define outq(v,c) ({ __io_pbw(); writeq_cpu((v),(void*)(c)); __io_paw(); }) 66*4882a593Smuzhiyun #endif 67*4882a593Smuzhiyun 68*4882a593Smuzhiyun /* 69*4882a593Smuzhiyun * Accesses from a single hart to a single I/O address must be ordered. This 70*4882a593Smuzhiyun * allows us to use the raw read macros, but we still need to fence before and 71*4882a593Smuzhiyun * after the block to ensure ordering WRT other macros. These are defined to 72*4882a593Smuzhiyun * perform host-endian accesses so we use __raw instead of __cpu. 73*4882a593Smuzhiyun */ 74*4882a593Smuzhiyun #define __io_reads_ins(port, ctype, len, bfence, afence) \ 75*4882a593Smuzhiyun static inline void __ ## port ## len(const volatile void __iomem *addr, \ 76*4882a593Smuzhiyun void *buffer, \ 77*4882a593Smuzhiyun unsigned int count) \ 78*4882a593Smuzhiyun { \ 79*4882a593Smuzhiyun bfence; \ 80*4882a593Smuzhiyun if (count) { \ 81*4882a593Smuzhiyun ctype *buf = buffer; \ 82*4882a593Smuzhiyun \ 83*4882a593Smuzhiyun do { \ 84*4882a593Smuzhiyun ctype x = __raw_read ## len(addr); \ 85*4882a593Smuzhiyun *buf++ = x; \ 86*4882a593Smuzhiyun } while (--count); \ 87*4882a593Smuzhiyun } \ 88*4882a593Smuzhiyun afence; \ 89*4882a593Smuzhiyun } 90*4882a593Smuzhiyun 91*4882a593Smuzhiyun #define __io_writes_outs(port, ctype, len, bfence, afence) \ 92*4882a593Smuzhiyun static inline void __ ## port ## len(volatile void __iomem *addr, \ 93*4882a593Smuzhiyun const void *buffer, \ 94*4882a593Smuzhiyun unsigned int count) \ 95*4882a593Smuzhiyun { \ 96*4882a593Smuzhiyun bfence; \ 97*4882a593Smuzhiyun if (count) { \ 98*4882a593Smuzhiyun const ctype *buf = buffer; \ 99*4882a593Smuzhiyun \ 100*4882a593Smuzhiyun do { \ 101*4882a593Smuzhiyun __raw_write ## len(*buf++, addr); \ 102*4882a593Smuzhiyun } while (--count); \ 103*4882a593Smuzhiyun } \ 104*4882a593Smuzhiyun afence; \ 105*4882a593Smuzhiyun } 106*4882a593Smuzhiyun 107*4882a593Smuzhiyun __io_reads_ins(reads, u8, b, __io_br(), __io_ar(addr)) 108*4882a593Smuzhiyun __io_reads_ins(reads, u16, w, __io_br(), __io_ar(addr)) 109*4882a593Smuzhiyun __io_reads_ins(reads, u32, l, __io_br(), __io_ar(addr)) 110*4882a593Smuzhiyun #define readsb(addr, buffer, count) __readsb(addr, buffer, count) 111*4882a593Smuzhiyun #define readsw(addr, buffer, count) __readsw(addr, buffer, count) 112*4882a593Smuzhiyun #define readsl(addr, buffer, count) __readsl(addr, buffer, count) 113*4882a593Smuzhiyun 114*4882a593Smuzhiyun __io_reads_ins(ins, u8, b, __io_pbr(), __io_par(addr)) 115*4882a593Smuzhiyun __io_reads_ins(ins, u16, w, __io_pbr(), __io_par(addr)) 116*4882a593Smuzhiyun __io_reads_ins(ins, u32, l, __io_pbr(), __io_par(addr)) 117*4882a593Smuzhiyun #define insb(addr, buffer, count) __insb(PCI_IOBASE + (addr), buffer, count) 118*4882a593Smuzhiyun #define insw(addr, buffer, count) __insw(PCI_IOBASE + (addr), buffer, count) 119*4882a593Smuzhiyun #define insl(addr, buffer, count) __insl(PCI_IOBASE + (addr), buffer, count) 120*4882a593Smuzhiyun 121*4882a593Smuzhiyun __io_writes_outs(writes, u8, b, __io_bw(), __io_aw()) 122*4882a593Smuzhiyun __io_writes_outs(writes, u16, w, __io_bw(), __io_aw()) 123*4882a593Smuzhiyun __io_writes_outs(writes, u32, l, __io_bw(), __io_aw()) 124*4882a593Smuzhiyun #define writesb(addr, buffer, count) __writesb(addr, buffer, count) 125*4882a593Smuzhiyun #define writesw(addr, buffer, count) __writesw(addr, buffer, count) 126*4882a593Smuzhiyun #define writesl(addr, buffer, count) __writesl(addr, buffer, count) 127*4882a593Smuzhiyun 128*4882a593Smuzhiyun __io_writes_outs(outs, u8, b, __io_pbw(), __io_paw()) 129*4882a593Smuzhiyun __io_writes_outs(outs, u16, w, __io_pbw(), __io_paw()) 130*4882a593Smuzhiyun __io_writes_outs(outs, u32, l, __io_pbw(), __io_paw()) 131*4882a593Smuzhiyun #define outsb(addr, buffer, count) __outsb(PCI_IOBASE + (addr), buffer, count) 132*4882a593Smuzhiyun #define outsw(addr, buffer, count) __outsw(PCI_IOBASE + (addr), buffer, count) 133*4882a593Smuzhiyun #define outsl(addr, buffer, count) __outsl(PCI_IOBASE + (addr), buffer, count) 134*4882a593Smuzhiyun 135*4882a593Smuzhiyun #ifdef CONFIG_64BIT 136*4882a593Smuzhiyun __io_reads_ins(reads, u64, q, __io_br(), __io_ar(addr)) 137*4882a593Smuzhiyun #define readsq(addr, buffer, count) __readsq(addr, buffer, count) 138*4882a593Smuzhiyun 139*4882a593Smuzhiyun __io_reads_ins(ins, u64, q, __io_pbr(), __io_par(addr)) 140*4882a593Smuzhiyun #define insq(addr, buffer, count) __insq(PCI_IOBASE + (addr), buffer, count) 141*4882a593Smuzhiyun 142*4882a593Smuzhiyun __io_writes_outs(writes, u64, q, __io_bw(), __io_aw()) 143*4882a593Smuzhiyun #define writesq(addr, buffer, count) __writesq(addr, buffer, count) 144*4882a593Smuzhiyun 145*4882a593Smuzhiyun __io_writes_outs(outs, u64, q, __io_pbr(), __io_paw()) 146*4882a593Smuzhiyun #define outsq(addr, buffer, count) __outsq(PCI_IOBASE + (addr), buffer, count) 147*4882a593Smuzhiyun #endif 148*4882a593Smuzhiyun 149*4882a593Smuzhiyun #include <asm-generic/io.h> 150*4882a593Smuzhiyun 151*4882a593Smuzhiyun #endif /* _ASM_RISCV_IO_H */ 152