1 /*
2  * Copyright (c) 2018, Pinecone Inc. and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <stddef.h>
8 #include <metal/cache.h>
9 #include <metal/io.h>
10 #include <nuttx/arch.h>
11 
metal_io_read_(struct metal_io_region * io,unsigned long offset,memory_order order,int width)12 static uint64_t metal_io_read_(struct metal_io_region *io,
13 			       unsigned long offset,
14 			       memory_order order,
15 			       int width)
16 {
17 	uint64_t value = 0;
18 	metal_unused(order);
19 
20 	metal_io_block_read(io, offset, &value, width);
21 	return value;
22 }
23 
metal_io_write_(struct metal_io_region * io,unsigned long offset,uint64_t value,memory_order order,int width)24 static void metal_io_write_(struct metal_io_region *io,
25 			    unsigned long offset,
26 			    uint64_t value,
27 			    memory_order order,
28 			    int width)
29 {
30 	metal_unused(order);
31 
32 	metal_io_block_write(io, offset, &value, width);
33 }
34 
metal_io_block_read_(struct metal_io_region * io,unsigned long offset,void * restrict dst,memory_order order,int len)35 static int metal_io_block_read_(struct metal_io_region *io,
36 				unsigned long offset,
37 				void *restrict dst,
38 				memory_order order,
39 				int len)
40 {
41 	void *va = metal_io_virt(io, offset);
42 	metal_unused(order);
43 
44 	metal_cache_invalidate(va, len);
45 	if (len == 1)
46 		*(uint8_t *)dst = *(uint8_t *)va;
47 	else if (len == 2)
48 		*(uint16_t *)dst = *(uint16_t *)va;
49 	else if (len == 4)
50 		*(uint32_t *)dst = *(uint32_t *)va;
51 	else if (len == 8) {
52 		*(uint32_t *)dst = *(uint32_t *)va;
53 		*((uint32_t *)dst + 1) = *((uint32_t *)va + 1);
54 	} else
55 		memcpy(dst, va, len);
56 
57 	return len;
58 }
59 
metal_io_block_write_(struct metal_io_region * io,unsigned long offset,const void * restrict src,memory_order order,int len)60 static int metal_io_block_write_(struct metal_io_region *io,
61 				 unsigned long offset,
62 				 const void *restrict src,
63 				 memory_order order,
64 				 int len)
65 {
66 	void *va = metal_io_virt(io, offset);
67 	metal_unused(order);
68 
69 	if (len == 1)
70 		*(uint8_t *)va = *(uint8_t *)src;
71 	else if (len == 2)
72 		*(uint16_t *)va = *(uint16_t *)src;
73 	else if (len == 4)
74 		*(uint32_t *)va = *(uint32_t *)src;
75 	else if (len == 8) {
76 		*(uint32_t *)va = *(uint32_t *)src;
77 		*((uint32_t *)va + 1) = *((uint32_t *)src + 1);
78 	} else
79 		memcpy(va, src, len);
80 
81 	metal_cache_flush(va, len);
82 
83 	return len;
84 }
85 
metal_io_block_set_(struct metal_io_region * io,unsigned long offset,unsigned char value,memory_order order,int len)86 static void metal_io_block_set_(struct metal_io_region *io,
87 				unsigned long offset,
88 				unsigned char value,
89 				memory_order order,
90 				int len)
91 {
92 	void *va = metal_io_virt(io, offset);
93 	metal_unused(order);
94 
95 	memset(va, value, len);
96 	metal_cache_flush(va, len);
97 }
98 
metal_io_close_(struct metal_io_region * io)99 static void metal_io_close_(struct metal_io_region *io)
100 {
101 	metal_unused(io);
102 }
103 
metal_io_offset_to_phys_(struct metal_io_region * io,unsigned long offset)104 static metal_phys_addr_t metal_io_offset_to_phys_(struct metal_io_region *io,
105 						  unsigned long offset)
106 {
107 	return up_addrenv_va_to_pa((void *)((uintptr_t)io->virt + offset));
108 }
109 
metal_io_phys_to_offset_(struct metal_io_region * io,metal_phys_addr_t phys)110 static unsigned long metal_io_phys_to_offset_(struct metal_io_region *io,
111 					      metal_phys_addr_t phys)
112 {
113 	return (uintptr_t)up_addrenv_pa_to_va(phys) - (uintptr_t)io->virt;
114 }
115 
116 static metal_phys_addr_t metal_io_phys_start_;
117 
118 static struct metal_io_region metal_io_region_ = {
119 	.virt = NULL,
120 	.physmap = &metal_io_phys_start_,
121 	.size = (size_t)-1,
122 	.page_shift = sizeof(metal_phys_addr_t) * CHAR_BIT,
123 	.page_mask = (metal_phys_addr_t)-1,
124 	.mem_flags = 0,
125 	.ops = {
126 		.read = metal_io_read_,
127 		.write = metal_io_write_,
128 		.block_read = metal_io_block_read_,
129 		.block_write = metal_io_block_write_,
130 		.block_set = metal_io_block_set_,
131 		.close = metal_io_close_,
132 		.offset_to_phys = metal_io_offset_to_phys_,
133 		.phys_to_offset = metal_io_phys_to_offset_,
134 	},
135 };
136 
metal_io_get_ops(void)137 struct metal_io_ops *metal_io_get_ops(void)
138 {
139 	return &metal_io_region_.ops;
140 }
141 
metal_io_get_region(void)142 struct metal_io_region *metal_io_get_region(void)
143 {
144 	return &metal_io_region_;
145 }
146