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