1 /*
2  * Support for Intel Camera Imaging ISP subsystem.
3  * Copyright (c) 2010 - 2015, Intel Corporation.
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms and conditions of the GNU General Public License,
7  * version 2, as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12  * more details.
13  */
14 
15 #include "type_support.h"
16 #include "queue_access.h"
17 #include "ia_css_circbuf.h"
18 #include "sp.h"
19 #include "memory_access.h"
20 #include "assert_support.h"
21 
22 int ia_css_queue_load(
23     struct ia_css_queue *rdesc,
24     ia_css_circbuf_desc_t *cb_desc,
25     uint32_t ignore_desc_flags)
26 {
27 	if (!rdesc || !cb_desc)
28 		return EINVAL;
29 
30 	if (rdesc->location == IA_CSS_QUEUE_LOC_SP) {
31 		assert(ignore_desc_flags <= QUEUE_IGNORE_DESC_FLAGS_MAX);
32 
33 		if (0 == (ignore_desc_flags & QUEUE_IGNORE_SIZE_FLAG)) {
34 			cb_desc->size = sp_dmem_load_uint8(rdesc->proc_id,
35 							   rdesc->desc.remote.cb_desc_addr
36 							   + offsetof(ia_css_circbuf_desc_t, size));
37 
38 			if (cb_desc->size == 0) {
39 				/* Adding back the workaround which was removed
40 				   while refactoring queues. When reading size
41 				   through sp_dmem_load_*, sometimes we get back
42 				   the value as zero. This causes division by 0
43 				   exception as the size is used in a modular
44 				   division operation. */
45 				return EDOM;
46 			}
47 		}
48 
49 		if (0 == (ignore_desc_flags & QUEUE_IGNORE_START_FLAG))
50 			cb_desc->start = sp_dmem_load_uint8(rdesc->proc_id,
51 							    rdesc->desc.remote.cb_desc_addr
52 							    + offsetof(ia_css_circbuf_desc_t, start));
53 
54 		if (0 == (ignore_desc_flags & QUEUE_IGNORE_END_FLAG))
55 			cb_desc->end = sp_dmem_load_uint8(rdesc->proc_id,
56 							  rdesc->desc.remote.cb_desc_addr
57 							  + offsetof(ia_css_circbuf_desc_t, end));
58 
59 		if (0 == (ignore_desc_flags & QUEUE_IGNORE_STEP_FLAG))
60 			cb_desc->step = sp_dmem_load_uint8(rdesc->proc_id,
61 							   rdesc->desc.remote.cb_desc_addr
62 							   + offsetof(ia_css_circbuf_desc_t, step));
63 
64 	} else if (rdesc->location == IA_CSS_QUEUE_LOC_HOST) {
65 		/* doing DMA transfer of entire structure */
66 		mmgr_load(rdesc->desc.remote.cb_desc_addr,
67 			  (void *)cb_desc,
68 			  sizeof(ia_css_circbuf_desc_t));
69 	} else if (rdesc->location == IA_CSS_QUEUE_LOC_ISP) {
70 		/* Not supported yet */
71 		return ENOTSUP;
72 	}
73 
74 	return 0;
75 }
76 
77 int ia_css_queue_store(
78     struct ia_css_queue *rdesc,
79     ia_css_circbuf_desc_t *cb_desc,
80     uint32_t ignore_desc_flags)
81 {
82 	if (!rdesc || !cb_desc)
83 		return EINVAL;
84 
85 	if (rdesc->location == IA_CSS_QUEUE_LOC_SP) {
86 		assert(ignore_desc_flags <= QUEUE_IGNORE_DESC_FLAGS_MAX);
87 
88 		if (0 == (ignore_desc_flags & QUEUE_IGNORE_SIZE_FLAG))
89 			sp_dmem_store_uint8(rdesc->proc_id,
90 					    rdesc->desc.remote.cb_desc_addr
91 					    + offsetof(ia_css_circbuf_desc_t, size),
92 					    cb_desc->size);
93 
94 		if (0 == (ignore_desc_flags & QUEUE_IGNORE_START_FLAG))
95 			sp_dmem_store_uint8(rdesc->proc_id,
96 					    rdesc->desc.remote.cb_desc_addr
97 					    + offsetof(ia_css_circbuf_desc_t, start),
98 					    cb_desc->start);
99 
100 		if (0 == (ignore_desc_flags & QUEUE_IGNORE_END_FLAG))
101 			sp_dmem_store_uint8(rdesc->proc_id,
102 					    rdesc->desc.remote.cb_desc_addr
103 					    + offsetof(ia_css_circbuf_desc_t, end),
104 					    cb_desc->end);
105 
106 		if (0 == (ignore_desc_flags & QUEUE_IGNORE_STEP_FLAG))
107 			sp_dmem_store_uint8(rdesc->proc_id,
108 					    rdesc->desc.remote.cb_desc_addr
109 					    + offsetof(ia_css_circbuf_desc_t, step),
110 					    cb_desc->step);
111 	} else if (rdesc->location == IA_CSS_QUEUE_LOC_HOST) {
112 		/* doing DMA transfer of entire structure */
113 		mmgr_store(rdesc->desc.remote.cb_desc_addr,
114 			   (void *)cb_desc,
115 			   sizeof(ia_css_circbuf_desc_t));
116 	} else if (rdesc->location == IA_CSS_QUEUE_LOC_ISP) {
117 		/* Not supported yet */
118 		return ENOTSUP;
119 	}
120 
121 	return 0;
122 }
123 
124 int ia_css_queue_item_load(
125     struct ia_css_queue *rdesc,
126     u8 position,
127     ia_css_circbuf_elem_t *item)
128 {
129 	if (!rdesc || !item)
130 		return EINVAL;
131 
132 	if (rdesc->location == IA_CSS_QUEUE_LOC_SP) {
133 		sp_dmem_load(rdesc->proc_id,
134 			     rdesc->desc.remote.cb_elems_addr
135 			     + position * sizeof(ia_css_circbuf_elem_t),
136 			     item,
137 			     sizeof(ia_css_circbuf_elem_t));
138 	} else if (rdesc->location == IA_CSS_QUEUE_LOC_HOST) {
139 		mmgr_load(rdesc->desc.remote.cb_elems_addr
140 			  + position * sizeof(ia_css_circbuf_elem_t),
141 			  (void *)item,
142 			  sizeof(ia_css_circbuf_elem_t));
143 	} else if (rdesc->location == IA_CSS_QUEUE_LOC_ISP) {
144 		/* Not supported yet */
145 		return ENOTSUP;
146 	}
147 
148 	return 0;
149 }
150 
151 int ia_css_queue_item_store(
152     struct ia_css_queue *rdesc,
153     u8 position,
154     ia_css_circbuf_elem_t *item)
155 {
156 	if (!rdesc || !item)
157 		return EINVAL;
158 
159 	if (rdesc->location == IA_CSS_QUEUE_LOC_SP) {
160 		sp_dmem_store(rdesc->proc_id,
161 			      rdesc->desc.remote.cb_elems_addr
162 			      + position * sizeof(ia_css_circbuf_elem_t),
163 			      item,
164 			      sizeof(ia_css_circbuf_elem_t));
165 	} else if (rdesc->location == IA_CSS_QUEUE_LOC_HOST) {
166 		mmgr_store(rdesc->desc.remote.cb_elems_addr
167 			   + position * sizeof(ia_css_circbuf_elem_t),
168 			   (void *)item,
169 			   sizeof(ia_css_circbuf_elem_t));
170 	} else if (rdesc->location == IA_CSS_QUEUE_LOC_ISP) {
171 		/* Not supported yet */
172 		return ENOTSUP;
173 	}
174 
175 	return 0;
176 }
177