162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com) 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#ifndef _ASM_ARC_IO_H 762306a36Sopenharmony_ci#define _ASM_ARC_IO_H 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/types.h> 1062306a36Sopenharmony_ci#include <asm/byteorder.h> 1162306a36Sopenharmony_ci#include <asm/page.h> 1262306a36Sopenharmony_ci#include <asm/unaligned.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#ifdef CONFIG_ISA_ARCV2 1562306a36Sopenharmony_ci#include <asm/barrier.h> 1662306a36Sopenharmony_ci#define __iormb() rmb() 1762306a36Sopenharmony_ci#define __iowmb() wmb() 1862306a36Sopenharmony_ci#else 1962306a36Sopenharmony_ci#define __iormb() do { } while (0) 2062306a36Sopenharmony_ci#define __iowmb() do { } while (0) 2162306a36Sopenharmony_ci#endif 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ciextern void __iomem *ioremap(phys_addr_t paddr, unsigned long size); 2462306a36Sopenharmony_ci#define ioremap ioremap 2562306a36Sopenharmony_ci#define ioremap_prot ioremap_prot 2662306a36Sopenharmony_ci#define iounmap iounmap 2762306a36Sopenharmony_cistatic inline void __iomem *ioport_map(unsigned long port, unsigned int nr) 2862306a36Sopenharmony_ci{ 2962306a36Sopenharmony_ci return (void __iomem *)port; 3062306a36Sopenharmony_ci} 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cistatic inline void ioport_unmap(void __iomem *addr) 3362306a36Sopenharmony_ci{ 3462306a36Sopenharmony_ci} 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci/* 3762306a36Sopenharmony_ci * io{read,write}{16,32}be() macros 3862306a36Sopenharmony_ci */ 3962306a36Sopenharmony_ci#define ioread16be(p) ({ u16 __v = be16_to_cpu((__force __be16)__raw_readw(p)); __iormb(); __v; }) 4062306a36Sopenharmony_ci#define ioread32be(p) ({ u32 __v = be32_to_cpu((__force __be32)__raw_readl(p)); __iormb(); __v; }) 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci#define iowrite16be(v,p) ({ __iowmb(); __raw_writew((__force u16)cpu_to_be16(v), p); }) 4362306a36Sopenharmony_ci#define iowrite32be(v,p) ({ __iowmb(); __raw_writel((__force u32)cpu_to_be32(v), p); }) 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci/* Change struct page to physical address */ 4662306a36Sopenharmony_ci#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT) 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#define __raw_readb __raw_readb 4962306a36Sopenharmony_cistatic inline u8 __raw_readb(const volatile void __iomem *addr) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci u8 b; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci __asm__ __volatile__( 5462306a36Sopenharmony_ci " ldb%U1 %0, %1 \n" 5562306a36Sopenharmony_ci : "=r" (b) 5662306a36Sopenharmony_ci : "m" (*(volatile u8 __force *)addr) 5762306a36Sopenharmony_ci : "memory"); 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci return b; 6062306a36Sopenharmony_ci} 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci#define __raw_readw __raw_readw 6362306a36Sopenharmony_cistatic inline u16 __raw_readw(const volatile void __iomem *addr) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci u16 s; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci __asm__ __volatile__( 6862306a36Sopenharmony_ci " ldw%U1 %0, %1 \n" 6962306a36Sopenharmony_ci : "=r" (s) 7062306a36Sopenharmony_ci : "m" (*(volatile u16 __force *)addr) 7162306a36Sopenharmony_ci : "memory"); 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci return s; 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci#define __raw_readl __raw_readl 7762306a36Sopenharmony_cistatic inline u32 __raw_readl(const volatile void __iomem *addr) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci u32 w; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci __asm__ __volatile__( 8262306a36Sopenharmony_ci " ld%U1 %0, %1 \n" 8362306a36Sopenharmony_ci : "=r" (w) 8462306a36Sopenharmony_ci : "m" (*(volatile u32 __force *)addr) 8562306a36Sopenharmony_ci : "memory"); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci return w; 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci/* 9162306a36Sopenharmony_ci * {read,write}s{b,w,l}() repeatedly access the same IO address in 9262306a36Sopenharmony_ci * native endianness in 8-, 16-, 32-bit chunks {into,from} memory, 9362306a36Sopenharmony_ci * @count times 9462306a36Sopenharmony_ci */ 9562306a36Sopenharmony_ci#define __raw_readsx(t,f) \ 9662306a36Sopenharmony_cistatic inline void __raw_reads##f(const volatile void __iomem *addr, \ 9762306a36Sopenharmony_ci void *ptr, unsigned int count) \ 9862306a36Sopenharmony_ci{ \ 9962306a36Sopenharmony_ci bool is_aligned = ((unsigned long)ptr % ((t) / 8)) == 0; \ 10062306a36Sopenharmony_ci u##t *buf = ptr; \ 10162306a36Sopenharmony_ci \ 10262306a36Sopenharmony_ci if (!count) \ 10362306a36Sopenharmony_ci return; \ 10462306a36Sopenharmony_ci \ 10562306a36Sopenharmony_ci /* Some ARC CPU's don't support unaligned accesses */ \ 10662306a36Sopenharmony_ci if (is_aligned) { \ 10762306a36Sopenharmony_ci do { \ 10862306a36Sopenharmony_ci u##t x = __raw_read##f(addr); \ 10962306a36Sopenharmony_ci *buf++ = x; \ 11062306a36Sopenharmony_ci } while (--count); \ 11162306a36Sopenharmony_ci } else { \ 11262306a36Sopenharmony_ci do { \ 11362306a36Sopenharmony_ci u##t x = __raw_read##f(addr); \ 11462306a36Sopenharmony_ci put_unaligned(x, buf++); \ 11562306a36Sopenharmony_ci } while (--count); \ 11662306a36Sopenharmony_ci } \ 11762306a36Sopenharmony_ci} 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci#define __raw_readsb __raw_readsb 12062306a36Sopenharmony_ci__raw_readsx(8, b) 12162306a36Sopenharmony_ci#define __raw_readsw __raw_readsw 12262306a36Sopenharmony_ci__raw_readsx(16, w) 12362306a36Sopenharmony_ci#define __raw_readsl __raw_readsl 12462306a36Sopenharmony_ci__raw_readsx(32, l) 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci#define __raw_writeb __raw_writeb 12762306a36Sopenharmony_cistatic inline void __raw_writeb(u8 b, volatile void __iomem *addr) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci __asm__ __volatile__( 13062306a36Sopenharmony_ci " stb%U1 %0, %1 \n" 13162306a36Sopenharmony_ci : 13262306a36Sopenharmony_ci : "r" (b), "m" (*(volatile u8 __force *)addr) 13362306a36Sopenharmony_ci : "memory"); 13462306a36Sopenharmony_ci} 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci#define __raw_writew __raw_writew 13762306a36Sopenharmony_cistatic inline void __raw_writew(u16 s, volatile void __iomem *addr) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci __asm__ __volatile__( 14062306a36Sopenharmony_ci " stw%U1 %0, %1 \n" 14162306a36Sopenharmony_ci : 14262306a36Sopenharmony_ci : "r" (s), "m" (*(volatile u16 __force *)addr) 14362306a36Sopenharmony_ci : "memory"); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci#define __raw_writel __raw_writel 14862306a36Sopenharmony_cistatic inline void __raw_writel(u32 w, volatile void __iomem *addr) 14962306a36Sopenharmony_ci{ 15062306a36Sopenharmony_ci __asm__ __volatile__( 15162306a36Sopenharmony_ci " st%U1 %0, %1 \n" 15262306a36Sopenharmony_ci : 15362306a36Sopenharmony_ci : "r" (w), "m" (*(volatile u32 __force *)addr) 15462306a36Sopenharmony_ci : "memory"); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci#define __raw_writesx(t,f) \ 15962306a36Sopenharmony_cistatic inline void __raw_writes##f(volatile void __iomem *addr, \ 16062306a36Sopenharmony_ci const void *ptr, unsigned int count) \ 16162306a36Sopenharmony_ci{ \ 16262306a36Sopenharmony_ci bool is_aligned = ((unsigned long)ptr % ((t) / 8)) == 0; \ 16362306a36Sopenharmony_ci const u##t *buf = ptr; \ 16462306a36Sopenharmony_ci \ 16562306a36Sopenharmony_ci if (!count) \ 16662306a36Sopenharmony_ci return; \ 16762306a36Sopenharmony_ci \ 16862306a36Sopenharmony_ci /* Some ARC CPU's don't support unaligned accesses */ \ 16962306a36Sopenharmony_ci if (is_aligned) { \ 17062306a36Sopenharmony_ci do { \ 17162306a36Sopenharmony_ci __raw_write##f(*buf++, addr); \ 17262306a36Sopenharmony_ci } while (--count); \ 17362306a36Sopenharmony_ci } else { \ 17462306a36Sopenharmony_ci do { \ 17562306a36Sopenharmony_ci __raw_write##f(get_unaligned(buf++), addr); \ 17662306a36Sopenharmony_ci } while (--count); \ 17762306a36Sopenharmony_ci } \ 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci#define __raw_writesb __raw_writesb 18162306a36Sopenharmony_ci__raw_writesx(8, b) 18262306a36Sopenharmony_ci#define __raw_writesw __raw_writesw 18362306a36Sopenharmony_ci__raw_writesx(16, w) 18462306a36Sopenharmony_ci#define __raw_writesl __raw_writesl 18562306a36Sopenharmony_ci__raw_writesx(32, l) 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci/* 18862306a36Sopenharmony_ci * MMIO can also get buffered/optimized in micro-arch, so barriers needed 18962306a36Sopenharmony_ci * Based on ARM model for the typical use case 19062306a36Sopenharmony_ci * 19162306a36Sopenharmony_ci * <ST [DMA buffer]> 19262306a36Sopenharmony_ci * <writel MMIO "go" reg> 19362306a36Sopenharmony_ci * or: 19462306a36Sopenharmony_ci * <readl MMIO "status" reg> 19562306a36Sopenharmony_ci * <LD [DMA buffer]> 19662306a36Sopenharmony_ci * 19762306a36Sopenharmony_ci * http://lkml.kernel.org/r/20150622133656.GG1583@arm.com 19862306a36Sopenharmony_ci */ 19962306a36Sopenharmony_ci#define readb(c) ({ u8 __v = readb_relaxed(c); __iormb(); __v; }) 20062306a36Sopenharmony_ci#define readw(c) ({ u16 __v = readw_relaxed(c); __iormb(); __v; }) 20162306a36Sopenharmony_ci#define readl(c) ({ u32 __v = readl_relaxed(c); __iormb(); __v; }) 20262306a36Sopenharmony_ci#define readsb(p,d,l) ({ __raw_readsb(p,d,l); __iormb(); }) 20362306a36Sopenharmony_ci#define readsw(p,d,l) ({ __raw_readsw(p,d,l); __iormb(); }) 20462306a36Sopenharmony_ci#define readsl(p,d,l) ({ __raw_readsl(p,d,l); __iormb(); }) 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci#define writeb(v,c) ({ __iowmb(); writeb_relaxed(v,c); }) 20762306a36Sopenharmony_ci#define writew(v,c) ({ __iowmb(); writew_relaxed(v,c); }) 20862306a36Sopenharmony_ci#define writel(v,c) ({ __iowmb(); writel_relaxed(v,c); }) 20962306a36Sopenharmony_ci#define writesb(p,d,l) ({ __iowmb(); __raw_writesb(p,d,l); }) 21062306a36Sopenharmony_ci#define writesw(p,d,l) ({ __iowmb(); __raw_writesw(p,d,l); }) 21162306a36Sopenharmony_ci#define writesl(p,d,l) ({ __iowmb(); __raw_writesl(p,d,l); }) 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci/* 21462306a36Sopenharmony_ci * Relaxed API for drivers which can handle barrier ordering themselves 21562306a36Sopenharmony_ci * 21662306a36Sopenharmony_ci * Also these are defined to perform little endian accesses. 21762306a36Sopenharmony_ci * To provide the typical device register semantics of fixed endian, 21862306a36Sopenharmony_ci * swap the byte order for Big Endian 21962306a36Sopenharmony_ci * 22062306a36Sopenharmony_ci * http://lkml.kernel.org/r/201603100845.30602.arnd@arndb.de 22162306a36Sopenharmony_ci */ 22262306a36Sopenharmony_ci#define readb_relaxed(c) __raw_readb(c) 22362306a36Sopenharmony_ci#define readw_relaxed(c) ({ u16 __r = le16_to_cpu((__force __le16) \ 22462306a36Sopenharmony_ci __raw_readw(c)); __r; }) 22562306a36Sopenharmony_ci#define readl_relaxed(c) ({ u32 __r = le32_to_cpu((__force __le32) \ 22662306a36Sopenharmony_ci __raw_readl(c)); __r; }) 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci#define writeb_relaxed(v,c) __raw_writeb(v,c) 22962306a36Sopenharmony_ci#define writew_relaxed(v,c) __raw_writew((__force u16) cpu_to_le16(v),c) 23062306a36Sopenharmony_ci#define writel_relaxed(v,c) __raw_writel((__force u32) cpu_to_le32(v),c) 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci#include <asm-generic/io.h> 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci#endif /* _ASM_ARC_IO_H */ 235