1 /*
2 Copyright (c) 2018, MIPI Alliance, Inc.
3 All rights reserved.
4 
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8 
9 * Redistributions of source code must retain the above copyright
10   notice, this list of conditions and the following disclaimer.
11 
12 * Redistributions in binary form must reproduce the above copyright
13   notice, this list of conditions and the following disclaimer in
14   the documentation and/or other materials provided with the
15   distribution.
16 
17 * Neither the name of the copyright holder nor the names of its
18   contributors may be used to endorse or promote products derived
19   from this software without specific prior written permission.
20 
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33 
34 /*
35  * Contributors:
36  * Norbert Schulz (Intel Corporation) - Initial API and implementation
37  */
38 #include "mipi_syst.h"
39 #include "mipi_syst/message.h"
40 #include "mipi_syst/crc32.h"
41 
42 #if defined(MIPI_SYST_PCFG_ENABLE_DEFAULT_SCATTER_WRITE)
43 
44  /** scatter write routine
45   *
46   * This function implements the scatter write algorithm that translates
47   * the logical SyS-T memory descriptor representation into output
48   * requests. The actual output routines are defined through
49   * the MIPI_SYST_OUTPUT_* definitions from the platform header file.
50   *
51   * @param systh used syst handle
52   * @param scatterprog message content write instructions
53   * @param pdesc pointer to memory area with message data
54   */
mipi_syst_scatter_write(struct mipi_syst_handle * systh,struct mipi_syst_scatter_prog * scatterprog,const void * pdesc)55 void mipi_syst_scatter_write(struct mipi_syst_handle* systh,
56 	struct mipi_syst_scatter_prog *scatterprog, const void *pdesc)
57 {
58 	unsigned int repeat;
59 
60 	/* Define an "any" size integer pointer to avoid casts and to simplify
61 	 * type based incrementing
62 	 */
63 	union {
64 		const void *vp;
65 		const mipi_syst_u8 *bp;
66 		const mipi_syst_u16 *hp;
67 		const mipi_syst_u32 *wp;
68 		const mipi_syst_u64 *dp;
69 	} data;
70 
71 #if defined(MIPI_SYST_PCFG_ENABLE_CHECKSUM)
72 #define IFDO(a, b)  { if (a) do { b; } while (0); }
73 
74 	 mipi_syst_u32 crc;
75 	int use_crc;
76 
77 	use_crc = systh->systh_tag.et_chksum;
78 	crc = MIPI_SYST_CRC32_INIT(0);
79 #else
80 
81 #define IFDO(a, b)
82 	/* no checksump computation support */
83 #endif
84 
85 	/* Write the "always" present tag field as a time-stamped D32 */
86 	MIPI_SYST_OUTPUT_D32TS(systh, *(mipi_syst_u32 *)pdesc);
87 
88 	IFDO(use_crc, MIPI_SYST_CRC32_U32(crc, *(mipi_syst_u32 *)pdesc));
89 
90 	/* Run the message scatter write program to dump the message contents
91 	 */
92 	while (scatterprog->sso_opcode != MIPI_SYST_SCATTER_OP_END) {
93 		repeat = scatterprog->sso_length;
94 		data.vp = pdesc;
95 		data.bp += scatterprog->sso_offset;
96 
97 		switch (scatterprog->sso_opcode) {
98 		case MIPI_SYST_SCATTER_OP_8BIT:
99 			do {
100 				MIPI_SYST_OUTPUT_D8(systh, *data.bp);
101 				IFDO(use_crc,
102 					MIPI_SYST_CRC32_U8(crc, *data.bp));
103 				++data.bp;
104 			} while (--repeat);
105 			break;
106 
107 		case MIPI_SYST_SCATTER_OP_16BIT:
108 			do {
109 				MIPI_SYST_OUTPUT_D16(systh, *data.hp);
110 				IFDO(use_crc,
111 					MIPI_SYST_CRC32_U16(crc, *data.hp));
112 				++data.hp;
113 			} while (--repeat);
114 			break;
115 
116 		case MIPI_SYST_SCATTER_OP_32BIT:
117 			do {
118 				MIPI_SYST_OUTPUT_D32(systh, *data.wp);
119 				IFDO(use_crc,
120 					MIPI_SYST_CRC32_U32(crc, *data.wp));
121 				++data.wp;
122 			} while (--repeat);
123 			break;
124 
125 
126 		case MIPI_SYST_SCATTER_OP_64BIT:
127 			do {
128 #if defined(MIPI_SYST_PCFG_ENABLE_64BIT_IO)
129 				MIPI_SYST_OUTPUT_D64(systh, *data.dp);
130 #else
131 #if defined(MIPI_SYST_BIG_ENDIAN)
132 				MIPI_SYST_OUTPUT_D32(systh, data.wp[1]);
133 				MIPI_SYST_OUTPUT_D32(systh, data.wp[0]);
134 #else
135 				MIPI_SYST_OUTPUT_D32(systh, data.wp[0]);
136 				MIPI_SYST_OUTPUT_D32(systh, data.wp[1]);
137 #endif
138 
139 #endif /* ! defined(MIPI_SYST_PCFG_ENABLE_64BIT_IO) */
140 				IFDO(use_crc,
141 					MIPI_SYST_CRC32_U64(crc, *data.dp));
142 				++data.dp;
143 			} while (--repeat);
144 			break;
145 
146 		case MIPI_SYST_SCATTER_OP_BLOB:
147 			/* data location is pointer to real data,
148 			 * not data itself
149 			 */
150 			data.vp = *(void **)data.vp;
151 
152 #if defined(MIPI_SYST_PCFG_ENABLE_64BIT_IO)
153 
154 			while (repeat >= sizeof(mipi_syst_u64)) {
155 				mipi_syst_u64 v;
156 				v = MIPI_SYST_HTOLE64(*data.dp);
157 				MIPI_SYST_OUTPUT_D64(systh, v);
158 				IFDO(use_crc,
159 					MIPI_SYST_CRC32_U64(crc, v));
160 				++data.dp;
161 				repeat -= sizeof(mipi_syst_u64);
162 			}
163 
164 			if (repeat >= sizeof(mipi_syst_u32)) {
165 				mipi_syst_u32 v;
166 				v = MIPI_SYST_HTOLE32(*data.wp);
167 				MIPI_SYST_OUTPUT_D32(systh, v);
168 				IFDO(use_crc,
169 					MIPI_SYST_CRC32_U32(crc,
170 						*data.wp));
171 				++data.wp;
172 				repeat -= sizeof(mipi_syst_u32);
173 			}
174 #else
175 			while (repeat >= sizeof(mipi_syst_u32)) {
176 				mipi_syst_u32 v;
177 				v = MIPI_SYST_HTOLE32(*data.wp);
178 				MIPI_SYST_OUTPUT_D32(systh, v);
179 
180 				IFDO(use_crc,
181 					MIPI_SYST_CRC32_U32(crc, v));
182 				++data.wp;
183 				repeat -= sizeof(mipi_syst_u32);
184 			}
185 #endif
186 			if (repeat >= sizeof(mipi_syst_u16)) {
187 				mipi_syst_u16 v;
188 				v = MIPI_SYST_HTOLE16(*data.hp);
189 				MIPI_SYST_OUTPUT_D16(systh, v);
190 
191 				IFDO(use_crc,
192 					MIPI_SYST_CRC32_U16(crc, v));
193 				++data.hp;
194 				repeat -= sizeof(mipi_syst_u16);
195 			}
196 
197 			if (repeat) {
198 				MIPI_SYST_OUTPUT_D8(systh,
199 					*data.bp);
200 				IFDO(use_crc,
201 					MIPI_SYST_CRC32_U8(crc,	*data.bp));
202 			}
203 			break;
204 		}
205 		++scatterprog;
206 	}
207 
208 #if defined(MIPI_SYST_PCFG_ENABLE_CHECKSUM)
209 	if (use_crc) {
210 		crc = MIPI_SYST_CRC32_GET(crc);
211 		MIPI_SYST_OUTPUT_D32(systh, crc);
212 	}
213 #endif
214 
215 	/* EVENT end of record mark */
216 	MIPI_SYST_OUTPUT_FLAG(systh);
217 }
218 
219 #endif /* defined(MIPI_SYST_PCFG_ENABLE_DEFAULT_SCATTER_WRITE) */