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 "hmm.h"
16 
17 #include "type_support.h"
18 #include "queue_access.h"
19 #include "ia_css_circbuf.h"
20 #include "sp.h"
21 #include "assert_support.h"
22 
23 int ia_css_queue_load(
24     struct ia_css_queue *rdesc,
25     ia_css_circbuf_desc_t *cb_desc,
26     uint32_t ignore_desc_flags)
27 {
28 	if (!rdesc || !cb_desc)
29 		return -EINVAL;
30 
31 	if (rdesc->location == IA_CSS_QUEUE_LOC_SP) {
32 		assert(ignore_desc_flags <= QUEUE_IGNORE_DESC_FLAGS_MAX);
33 
34 		if (0 == (ignore_desc_flags & QUEUE_IGNORE_SIZE_FLAG)) {
35 			cb_desc->size = sp_dmem_load_uint8(rdesc->proc_id,
36 							   rdesc->desc.remote.cb_desc_addr
37 							   + offsetof(ia_css_circbuf_desc_t, size));
38 
39 			if (cb_desc->size == 0) {
40 				/* Adding back the workaround which was removed
41 				   while refactoring queues. When reading size
42 				   through sp_dmem_load_*, sometimes we get back
43 				   the value as zero. This causes division by 0
44 				   exception as the size is used in a modular
45 				   division operation. */
46 				return EDOM;
47 			}
48 		}
49 
50 		if (0 == (ignore_desc_flags & QUEUE_IGNORE_START_FLAG))
51 			cb_desc->start = sp_dmem_load_uint8(rdesc->proc_id,
52 							    rdesc->desc.remote.cb_desc_addr
53 							    + offsetof(ia_css_circbuf_desc_t, start));
54 
55 		if (0 == (ignore_desc_flags & QUEUE_IGNORE_END_FLAG))
56 			cb_desc->end = sp_dmem_load_uint8(rdesc->proc_id,
57 							  rdesc->desc.remote.cb_desc_addr
58 							  + offsetof(ia_css_circbuf_desc_t, end));
59 
60 		if (0 == (ignore_desc_flags & QUEUE_IGNORE_STEP_FLAG))
61 			cb_desc->step = sp_dmem_load_uint8(rdesc->proc_id,
62 							   rdesc->desc.remote.cb_desc_addr
63 							   + offsetof(ia_css_circbuf_desc_t, step));
64 
65 	} else if (rdesc->location == IA_CSS_QUEUE_LOC_HOST) {
66 		/* doing DMA transfer of entire structure */
67 		hmm_load(rdesc->desc.remote.cb_desc_addr,
68 			  (void *)cb_desc,
69 			  sizeof(ia_css_circbuf_desc_t));
70 	} else if (rdesc->location == IA_CSS_QUEUE_LOC_ISP) {
71 		/* Not supported yet */
72 		return -ENOTSUPP;
73 	}
74 
75 	return 0;
76 }
77 
78 int ia_css_queue_store(
79     struct ia_css_queue *rdesc,
80     ia_css_circbuf_desc_t *cb_desc,
81     uint32_t ignore_desc_flags)
82 {
83 	if (!rdesc || !cb_desc)
84 		return -EINVAL;
85 
86 	if (rdesc->location == IA_CSS_QUEUE_LOC_SP) {
87 		assert(ignore_desc_flags <= QUEUE_IGNORE_DESC_FLAGS_MAX);
88 
89 		if (0 == (ignore_desc_flags & QUEUE_IGNORE_SIZE_FLAG))
90 			sp_dmem_store_uint8(rdesc->proc_id,
91 					    rdesc->desc.remote.cb_desc_addr
92 					    + offsetof(ia_css_circbuf_desc_t, size),
93 					    cb_desc->size);
94 
95 		if (0 == (ignore_desc_flags & QUEUE_IGNORE_START_FLAG))
96 			sp_dmem_store_uint8(rdesc->proc_id,
97 					    rdesc->desc.remote.cb_desc_addr
98 					    + offsetof(ia_css_circbuf_desc_t, start),
99 					    cb_desc->start);
100 
101 		if (0 == (ignore_desc_flags & QUEUE_IGNORE_END_FLAG))
102 			sp_dmem_store_uint8(rdesc->proc_id,
103 					    rdesc->desc.remote.cb_desc_addr
104 					    + offsetof(ia_css_circbuf_desc_t, end),
105 					    cb_desc->end);
106 
107 		if (0 == (ignore_desc_flags & QUEUE_IGNORE_STEP_FLAG))
108 			sp_dmem_store_uint8(rdesc->proc_id,
109 					    rdesc->desc.remote.cb_desc_addr
110 					    + offsetof(ia_css_circbuf_desc_t, step),
111 					    cb_desc->step);
112 	} else if (rdesc->location == IA_CSS_QUEUE_LOC_HOST) {
113 		/* doing DMA transfer of entire structure */
114 		hmm_store(rdesc->desc.remote.cb_desc_addr,
115 			   (void *)cb_desc,
116 			   sizeof(ia_css_circbuf_desc_t));
117 	} else if (rdesc->location == IA_CSS_QUEUE_LOC_ISP) {
118 		/* Not supported yet */
119 		return -ENOTSUPP;
120 	}
121 
122 	return 0;
123 }
124 
125 int ia_css_queue_item_load(
126     struct ia_css_queue *rdesc,
127     u8 position,
128     ia_css_circbuf_elem_t *item)
129 {
130 	if (!rdesc || !item)
131 		return -EINVAL;
132 
133 	if (rdesc->location == IA_CSS_QUEUE_LOC_SP) {
134 		sp_dmem_load(rdesc->proc_id,
135 			     rdesc->desc.remote.cb_elems_addr
136 			     + position * sizeof(ia_css_circbuf_elem_t),
137 			     item,
138 			     sizeof(ia_css_circbuf_elem_t));
139 	} else if (rdesc->location == IA_CSS_QUEUE_LOC_HOST) {
140 		hmm_load(rdesc->desc.remote.cb_elems_addr
141 			  + position * sizeof(ia_css_circbuf_elem_t),
142 			  (void *)item,
143 			  sizeof(ia_css_circbuf_elem_t));
144 	} else if (rdesc->location == IA_CSS_QUEUE_LOC_ISP) {
145 		/* Not supported yet */
146 		return -ENOTSUPP;
147 	}
148 
149 	return 0;
150 }
151 
152 int ia_css_queue_item_store(
153     struct ia_css_queue *rdesc,
154     u8 position,
155     ia_css_circbuf_elem_t *item)
156 {
157 	if (!rdesc || !item)
158 		return -EINVAL;
159 
160 	if (rdesc->location == IA_CSS_QUEUE_LOC_SP) {
161 		sp_dmem_store(rdesc->proc_id,
162 			      rdesc->desc.remote.cb_elems_addr
163 			      + position * sizeof(ia_css_circbuf_elem_t),
164 			      item,
165 			      sizeof(ia_css_circbuf_elem_t));
166 	} else if (rdesc->location == IA_CSS_QUEUE_LOC_HOST) {
167 		hmm_store(rdesc->desc.remote.cb_elems_addr
168 			   + position * sizeof(ia_css_circbuf_elem_t),
169 			   (void *)item,
170 			   sizeof(ia_css_circbuf_elem_t));
171 	} else if (rdesc->location == IA_CSS_QUEUE_LOC_ISP) {
172 		/* Not supported yet */
173 		return -ENOTSUPP;
174 	}
175 
176 	return 0;
177 }
178