Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

soundwire: cadence: add BTP/BRA helpers to format data

The Cadence IP expects a specific format (detailed in the
Documentation). Add helpers to copy the data into the DMA buffer.

The crc8 table is for now only used by the Cadence driver. This table
might be moved to a common module at a later point if needed by other
controller implementations.

Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.dev>
Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: Liam Girdwood <liam.r.girdwood@intel.com>
Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Tested-by: shumingf@realtek.com
Link: https://lore.kernel.org/r/20250227140615.8147-10-yung-chuan.liao@linux.intel.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>

authored by

Pierre-Louis Bossart and committed by
Vinod Koul
8eb5d7ad 8e4a239b

+655
+1
drivers/soundwire/Kconfig
··· 31 31 32 32 config SOUNDWIRE_CADENCE 33 33 tristate 34 + select CRC8 34 35 35 36 config SOUNDWIRE_INTEL 36 37 tristate "Intel SoundWire Master driver"
+634
drivers/soundwire/cadence_master.c
··· 7 7 */ 8 8 9 9 #include <linux/cleanup.h> 10 + #include <linux/crc8.h> 10 11 #include <linux/delay.h> 11 12 #include <linux/device.h> 12 13 #include <linux/debugfs.h> ··· 1976 1975 return pdi; 1977 1976 } 1978 1977 EXPORT_SYMBOL(sdw_cdns_alloc_pdi); 1978 + 1979 + /* 1980 + * the MIPI SoundWire CRC8 polynomial is X^8 + X^6 + X^3 + X^2 + 1, MSB first 1981 + * The value is (1)01001101 = 0x4D 1982 + * 1983 + * the table below was generated with 1984 + * 1985 + * u8 crc8_lookup_table[CRC8_TABLE_SIZE]; 1986 + * crc8_populate_msb(crc8_lookup_table, SDW_CRC8_POLY); 1987 + * 1988 + */ 1989 + #define SDW_CRC8_SEED 0xFF 1990 + #define SDW_CRC8_POLY 0x4D 1991 + 1992 + static const u8 sdw_crc8_lookup_msb[CRC8_TABLE_SIZE] = { 1993 + 0x00, 0x4d, 0x9a, 0xd7, 0x79, 0x34, 0xe3, 0xae, /* 0 - 7 */ 1994 + 0xf2, 0xbf, 0x68, 0x25, 0x8b, 0xc6, 0x11, 0x5c, /* 8 -15 */ 1995 + 0xa9, 0xe4, 0x33, 0x7e, 0xd0, 0x9d, 0x4a, 0x07, /* 16 - 23 */ 1996 + 0x5b, 0x16, 0xc1, 0x8c, 0x22, 0x6f, 0xb8, 0xf5, /* 24 - 31 */ 1997 + 0x1f, 0x52, 0x85, 0xc8, 0x66, 0x2b, 0xfc, 0xb1, /* 32 - 39 */ 1998 + 0xed, 0xa0, 0x77, 0x3a, 0x94, 0xd9, 0x0e, 0x43, /* 40 - 47 */ 1999 + 0xb6, 0xfb, 0x2c, 0x61, 0xcf, 0x82, 0x55, 0x18, /* 48 - 55 */ 2000 + 0x44, 0x09, 0xde, 0x93, 0x3d, 0x70, 0xa7, 0xea, /* 56 - 63 */ 2001 + 0x3e, 0x73, 0xa4, 0xe9, 0x47, 0x0a, 0xdd, 0x90, /* 64 - 71 */ 2002 + 0xcc, 0x81, 0x56, 0x1b, 0xb5, 0xf8, 0x2f, 0x62, /* 72 - 79 */ 2003 + 0x97, 0xda, 0x0d, 0x40, 0xee, 0xa3, 0x74, 0x39, /* 80 - 87 */ 2004 + 0x65, 0x28, 0xff, 0xb2, 0x1c, 0x51, 0x86, 0xcb, /* 88 - 95 */ 2005 + 0x21, 0x6c, 0xbb, 0xf6, 0x58, 0x15, 0xc2, 0x8f, /* 96 - 103 */ 2006 + 0xd3, 0x9e, 0x49, 0x04, 0xaa, 0xe7, 0x30, 0x7d, /* 104 - 111 */ 2007 + 0x88, 0xc5, 0x12, 0x5f, 0xf1, 0xbc, 0x6b, 0x26, /* 112 - 119 */ 2008 + 0x7a, 0x37, 0xe0, 0xad, 0x03, 0x4e, 0x99, 0xd4, /* 120 - 127 */ 2009 + 0x7c, 0x31, 0xe6, 0xab, 0x05, 0x48, 0x9f, 0xd2, /* 128 - 135 */ 2010 + 0x8e, 0xc3, 0x14, 0x59, 0xf7, 0xba, 0x6d, 0x20, /* 136 - 143 */ 2011 + 0xd5, 0x98, 0x4f, 0x02, 0xac, 0xe1, 0x36, 0x7b, /* 144 - 151 */ 2012 + 0x27, 0x6a, 0xbd, 0xf0, 0x5e, 0x13, 0xc4, 0x89, /* 152 - 159 */ 2013 + 0x63, 0x2e, 0xf9, 0xb4, 0x1a, 0x57, 0x80, 0xcd, /* 160 - 167 */ 2014 + 0x91, 0xdc, 0x0b, 0x46, 0xe8, 0xa5, 0x72, 0x3f, /* 168 - 175 */ 2015 + 0xca, 0x87, 0x50, 0x1d, 0xb3, 0xfe, 0x29, 0x64, /* 176 - 183 */ 2016 + 0x38, 0x75, 0xa2, 0xef, 0x41, 0x0c, 0xdb, 0x96, /* 184 - 191 */ 2017 + 0x42, 0x0f, 0xd8, 0x95, 0x3b, 0x76, 0xa1, 0xec, /* 192 - 199 */ 2018 + 0xb0, 0xfd, 0x2a, 0x67, 0xc9, 0x84, 0x53, 0x1e, /* 200 - 207 */ 2019 + 0xeb, 0xa6, 0x71, 0x3c, 0x92, 0xdf, 0x08, 0x45, /* 208 - 215 */ 2020 + 0x19, 0x54, 0x83, 0xce, 0x60, 0x2d, 0xfa, 0xb7, /* 216 - 223 */ 2021 + 0x5d, 0x10, 0xc7, 0x8a, 0x24, 0x69, 0xbe, 0xf3, /* 224 - 231 */ 2022 + 0xaf, 0xe2, 0x35, 0x78, 0xd6, 0x9b, 0x4c, 0x01, /* 232 - 239 */ 2023 + 0xf4, 0xb9, 0x6e, 0x23, 0x8d, 0xc0, 0x17, 0x5a, /* 240 - 247 */ 2024 + 0x06, 0x4b, 0x9c, 0xd1, 0x7f, 0x32, 0xe5, 0xa8 /* 248 - 255 */ 2025 + }; 2026 + 2027 + /* BPT/BRA helpers */ 2028 + 2029 + #define SDW_CDNS_BRA_HDR 6 /* defined by MIPI */ 2030 + #define SDW_CDNS_BRA_HDR_CRC 1 /* defined by MIPI */ 2031 + #define SDW_CDNS_BRA_HDR_CRC_PAD 1 /* Cadence only */ 2032 + #define SDW_CDNS_BRA_HDR_RESP 1 /* defined by MIPI */ 2033 + #define SDW_CDNS_BRA_HDR_RESP_PAD 1 /* Cadence only */ 2034 + 2035 + #define SDW_CDNS_BRA_DATA_PAD 1 /* Cadence only */ 2036 + #define SDW_CDNS_BRA_DATA_CRC 1 /* defined by MIPI */ 2037 + #define SDW_CDNS_BRA_DATA_CRC_PAD 1 /* Cadence only */ 2038 + 2039 + #define SDW_CDNS_BRA_FOOTER_RESP 1 /* defined by MIPI */ 2040 + #define SDW_CDNS_BRA_FOOTER_RESP_PAD 1 /* Cadence only */ 2041 + 2042 + #define SDW_CDNS_WRITE_PDI1_BUFFER_SIZE \ 2043 + ((SDW_CDNS_BRA_HDR_RESP + SDW_CDNS_BRA_HDR_RESP_PAD + \ 2044 + SDW_CDNS_BRA_FOOTER_RESP + SDW_CDNS_BRA_FOOTER_RESP_PAD) * 2) 2045 + 2046 + #define SDW_CDNS_READ_PDI0_BUFFER_SIZE \ 2047 + ((SDW_CDNS_BRA_HDR + SDW_CDNS_BRA_HDR_CRC + SDW_CDNS_BRA_HDR_CRC_PAD) * 2) 2048 + 2049 + static unsigned int sdw_cdns_bra_actual_data_size(unsigned int allocated_bytes_per_frame) 2050 + { 2051 + unsigned int total; 2052 + 2053 + if (allocated_bytes_per_frame < (SDW_CDNS_BRA_HDR + SDW_CDNS_BRA_HDR_CRC + 2054 + SDW_CDNS_BRA_HDR_RESP + SDW_CDNS_BRA_DATA_CRC + 2055 + SDW_CDNS_BRA_FOOTER_RESP)) 2056 + return 0; 2057 + 2058 + total = allocated_bytes_per_frame - SDW_CDNS_BRA_HDR - SDW_CDNS_BRA_HDR_CRC - 2059 + SDW_CDNS_BRA_HDR_RESP - SDW_CDNS_BRA_DATA_CRC - SDW_CDNS_BRA_FOOTER_RESP; 2060 + 2061 + return total; 2062 + } 2063 + 2064 + static unsigned int sdw_cdns_write_pdi0_buffer_size(unsigned int actual_data_size) 2065 + { 2066 + unsigned int total; 2067 + 2068 + total = SDW_CDNS_BRA_HDR + SDW_CDNS_BRA_HDR_CRC + SDW_CDNS_BRA_HDR_CRC_PAD; 2069 + 2070 + total += actual_data_size; 2071 + if (actual_data_size & 1) 2072 + total += SDW_CDNS_BRA_DATA_PAD; 2073 + 2074 + total += SDW_CDNS_BRA_DATA_CRC + SDW_CDNS_BRA_DATA_CRC_PAD; 2075 + 2076 + return total * 2; 2077 + } 2078 + 2079 + static unsigned int sdw_cdns_read_pdi1_buffer_size(unsigned int actual_data_size) 2080 + { 2081 + unsigned int total; 2082 + 2083 + total = SDW_CDNS_BRA_HDR_RESP + SDW_CDNS_BRA_HDR_RESP_PAD; 2084 + 2085 + total += actual_data_size; 2086 + if (actual_data_size & 1) 2087 + total += SDW_CDNS_BRA_DATA_PAD; 2088 + 2089 + total += SDW_CDNS_BRA_HDR_CRC + SDW_CDNS_BRA_HDR_CRC_PAD; 2090 + 2091 + total += SDW_CDNS_BRA_FOOTER_RESP + SDW_CDNS_BRA_FOOTER_RESP_PAD; 2092 + 2093 + return total * 2; 2094 + } 2095 + 2096 + int sdw_cdns_bpt_find_buffer_sizes(int command, /* 0: write, 1: read */ 2097 + int row, int col, unsigned int data_bytes, 2098 + unsigned int requested_bytes_per_frame, 2099 + unsigned int *data_per_frame, unsigned int *pdi0_buffer_size, 2100 + unsigned int *pdi1_buffer_size, unsigned int *num_frames) 2101 + { 2102 + unsigned int bpt_bits = row * (col - 1); 2103 + unsigned int bpt_bytes = bpt_bits >> 3; 2104 + unsigned int actual_bpt_bytes; 2105 + unsigned int pdi0_tx_size; 2106 + unsigned int pdi1_rx_size; 2107 + unsigned int remainder; 2108 + 2109 + if (!data_bytes) 2110 + return -EINVAL; 2111 + 2112 + actual_bpt_bytes = sdw_cdns_bra_actual_data_size(bpt_bytes); 2113 + if (!actual_bpt_bytes) 2114 + return -EINVAL; 2115 + 2116 + if (data_bytes < actual_bpt_bytes) 2117 + actual_bpt_bytes = data_bytes; 2118 + 2119 + /* 2120 + * the caller may want to set the number of bytes per frame, 2121 + * allow when possible 2122 + */ 2123 + if (requested_bytes_per_frame < actual_bpt_bytes) 2124 + actual_bpt_bytes = requested_bytes_per_frame; 2125 + 2126 + *data_per_frame = actual_bpt_bytes; 2127 + 2128 + if (command == 0) { 2129 + /* 2130 + * for writes we need to send all the data_bytes per frame, 2131 + * even for the last frame which may only transport fewer bytes 2132 + */ 2133 + 2134 + *num_frames = DIV_ROUND_UP(data_bytes, actual_bpt_bytes); 2135 + 2136 + pdi0_tx_size = sdw_cdns_write_pdi0_buffer_size(actual_bpt_bytes); 2137 + pdi1_rx_size = SDW_CDNS_WRITE_PDI1_BUFFER_SIZE; 2138 + 2139 + *pdi0_buffer_size = pdi0_tx_size * *num_frames; 2140 + *pdi1_buffer_size = pdi1_rx_size * *num_frames; 2141 + } else { 2142 + /* 2143 + * for reads we need to retrieve only what is requested in the BPT 2144 + * header, so the last frame needs to be special-cased 2145 + */ 2146 + *num_frames = data_bytes / actual_bpt_bytes; 2147 + 2148 + pdi0_tx_size = SDW_CDNS_READ_PDI0_BUFFER_SIZE; 2149 + pdi1_rx_size = sdw_cdns_read_pdi1_buffer_size(actual_bpt_bytes); 2150 + 2151 + *pdi0_buffer_size = pdi0_tx_size * *num_frames; 2152 + *pdi1_buffer_size = pdi1_rx_size * *num_frames; 2153 + 2154 + remainder = data_bytes % actual_bpt_bytes; 2155 + if (remainder) { 2156 + pdi0_tx_size = SDW_CDNS_READ_PDI0_BUFFER_SIZE; 2157 + pdi1_rx_size = sdw_cdns_read_pdi1_buffer_size(remainder); 2158 + 2159 + *num_frames = *num_frames + 1; 2160 + *pdi0_buffer_size += pdi0_tx_size; 2161 + *pdi1_buffer_size += pdi1_rx_size; 2162 + } 2163 + } 2164 + 2165 + return 0; 2166 + } 2167 + EXPORT_SYMBOL(sdw_cdns_bpt_find_buffer_sizes); 2168 + 2169 + static int sdw_cdns_copy_write_data(u8 *data, int data_size, u8 *dma_buffer, int dma_buffer_size) 2170 + { 2171 + /* 2172 + * the implementation copies the data one byte at a time. Experiments with 2173 + * two bytes at a time did not seem to improve the performance 2174 + */ 2175 + int i, j; 2176 + 2177 + /* size check to prevent out of bounds access */ 2178 + i = data_size - 1; 2179 + j = (2 * i) - (i & 1); 2180 + if (data_size & 1) 2181 + j++; 2182 + j += 2; 2183 + if (j >= dma_buffer_size) 2184 + return -EINVAL; 2185 + 2186 + /* copy data */ 2187 + for (i = 0; i < data_size; i++) { 2188 + j = (2 * i) - (i & 1); 2189 + dma_buffer[j] = data[i]; 2190 + } 2191 + /* add required pad */ 2192 + if (data_size & 1) 2193 + dma_buffer[++j] = 0; 2194 + /* skip last two bytes */ 2195 + j += 2; 2196 + 2197 + /* offset and data are off-by-one */ 2198 + return j + 1; 2199 + } 2200 + 2201 + static int sdw_cdns_prepare_write_pd0_buffer(u8 *header, unsigned int header_size, 2202 + u8 *data, unsigned int data_size, 2203 + u8 *dma_buffer, unsigned int dma_buffer_size, 2204 + unsigned int *dma_data_written, 2205 + unsigned int frame_counter) 2206 + { 2207 + int data_written; 2208 + u8 *last_byte; 2209 + u8 crc; 2210 + 2211 + *dma_data_written = 0; 2212 + 2213 + data_written = sdw_cdns_copy_write_data(header, header_size, dma_buffer, dma_buffer_size); 2214 + if (data_written < 0) 2215 + return data_written; 2216 + dma_buffer[3] = BIT(7); 2217 + dma_buffer[3] |= frame_counter & GENMASK(3, 0); 2218 + 2219 + dma_buffer += data_written; 2220 + dma_buffer_size -= data_written; 2221 + *dma_data_written += data_written; 2222 + 2223 + crc = SDW_CRC8_SEED; 2224 + crc = crc8(sdw_crc8_lookup_msb, header, header_size, crc); 2225 + 2226 + data_written = sdw_cdns_copy_write_data(&crc, 1, dma_buffer, dma_buffer_size); 2227 + if (data_written < 0) 2228 + return data_written; 2229 + dma_buffer += data_written; 2230 + dma_buffer_size -= data_written; 2231 + *dma_data_written += data_written; 2232 + 2233 + data_written = sdw_cdns_copy_write_data(data, data_size, dma_buffer, dma_buffer_size); 2234 + if (data_written < 0) 2235 + return data_written; 2236 + dma_buffer += data_written; 2237 + dma_buffer_size -= data_written; 2238 + *dma_data_written += data_written; 2239 + 2240 + crc = SDW_CRC8_SEED; 2241 + crc = crc8(sdw_crc8_lookup_msb, data, data_size, crc); 2242 + data_written = sdw_cdns_copy_write_data(&crc, 1, dma_buffer, dma_buffer_size); 2243 + if (data_written < 0) 2244 + return data_written; 2245 + dma_buffer += data_written; 2246 + dma_buffer_size -= data_written; 2247 + *dma_data_written += data_written; 2248 + 2249 + /* tag last byte */ 2250 + last_byte = dma_buffer - 1; 2251 + last_byte[0] = BIT(6); 2252 + 2253 + return 0; 2254 + } 2255 + 2256 + static int sdw_cdns_prepare_read_pd0_buffer(u8 *header, unsigned int header_size, 2257 + u8 *dma_buffer, unsigned int dma_buffer_size, 2258 + unsigned int *dma_data_written, 2259 + unsigned int frame_counter) 2260 + { 2261 + int data_written; 2262 + u8 *last_byte; 2263 + u8 crc; 2264 + 2265 + *dma_data_written = 0; 2266 + 2267 + data_written = sdw_cdns_copy_write_data(header, header_size, dma_buffer, dma_buffer_size); 2268 + if (data_written < 0) 2269 + return data_written; 2270 + dma_buffer[3] = BIT(7); 2271 + dma_buffer[3] |= frame_counter & GENMASK(3, 0); 2272 + 2273 + dma_buffer += data_written; 2274 + dma_buffer_size -= data_written; 2275 + *dma_data_written += data_written; 2276 + 2277 + crc = SDW_CRC8_SEED; 2278 + crc = crc8(sdw_crc8_lookup_msb, header, header_size, crc); 2279 + 2280 + data_written = sdw_cdns_copy_write_data(&crc, 1, dma_buffer, dma_buffer_size); 2281 + if (data_written < 0) 2282 + return data_written; 2283 + dma_buffer += data_written; 2284 + dma_buffer_size -= data_written; 2285 + *dma_data_written += data_written; 2286 + 2287 + /* tag last byte */ 2288 + last_byte = dma_buffer - 1; 2289 + last_byte[0] = BIT(6); 2290 + 2291 + return 0; 2292 + } 2293 + 2294 + #define CDNS_BPT_ROLLING_COUNTER_START 1 2295 + 2296 + int sdw_cdns_prepare_write_dma_buffer(u8 dev_num, u32 start_register, u8 *data, int data_size, 2297 + int data_per_frame, u8 *dma_buffer, int dma_buffer_size, 2298 + int *dma_buffer_total_bytes) 2299 + { 2300 + int total_dma_data_written = 0; 2301 + u8 *p_dma_buffer = dma_buffer; 2302 + u8 header[SDW_CDNS_BRA_HDR]; 2303 + int dma_data_written; 2304 + u8 *p_data = data; 2305 + u8 counter; 2306 + int ret; 2307 + 2308 + counter = CDNS_BPT_ROLLING_COUNTER_START; 2309 + 2310 + header[0] = BIT(1); /* write command: BIT(1) set */ 2311 + header[0] |= GENMASK(7, 6); /* header is active */ 2312 + header[0] |= (dev_num << 2); 2313 + 2314 + while (data_size >= data_per_frame) { 2315 + header[1] = data_per_frame; 2316 + header[2] = start_register >> 24 & 0xFF; 2317 + header[3] = start_register >> 16 & 0xFF; 2318 + header[4] = start_register >> 8 & 0xFF; 2319 + header[5] = start_register >> 0 & 0xFF; 2320 + 2321 + ret = sdw_cdns_prepare_write_pd0_buffer(header, SDW_CDNS_BRA_HDR, 2322 + p_data, data_per_frame, 2323 + p_dma_buffer, dma_buffer_size, 2324 + &dma_data_written, counter); 2325 + if (ret < 0) 2326 + return ret; 2327 + 2328 + counter++; 2329 + 2330 + p_data += data_per_frame; 2331 + data_size -= data_per_frame; 2332 + 2333 + p_dma_buffer += dma_data_written; 2334 + dma_buffer_size -= dma_data_written; 2335 + total_dma_data_written += dma_data_written; 2336 + 2337 + start_register += data_per_frame; 2338 + } 2339 + 2340 + if (data_size) { 2341 + header[1] = data_size; 2342 + header[2] = start_register >> 24 & 0xFF; 2343 + header[3] = start_register >> 16 & 0xFF; 2344 + header[4] = start_register >> 8 & 0xFF; 2345 + header[5] = start_register >> 0 & 0xFF; 2346 + 2347 + ret = sdw_cdns_prepare_write_pd0_buffer(header, SDW_CDNS_BRA_HDR, 2348 + p_data, data_size, 2349 + p_dma_buffer, dma_buffer_size, 2350 + &dma_data_written, counter); 2351 + if (ret < 0) 2352 + return ret; 2353 + 2354 + total_dma_data_written += dma_data_written; 2355 + } 2356 + 2357 + *dma_buffer_total_bytes = total_dma_data_written; 2358 + 2359 + return 0; 2360 + } 2361 + EXPORT_SYMBOL(sdw_cdns_prepare_write_dma_buffer); 2362 + 2363 + int sdw_cdns_prepare_read_dma_buffer(u8 dev_num, u32 start_register, int data_size, 2364 + int data_per_frame, u8 *dma_buffer, int dma_buffer_size, 2365 + int *dma_buffer_total_bytes) 2366 + { 2367 + int total_dma_data_written = 0; 2368 + u8 *p_dma_buffer = dma_buffer; 2369 + u8 header[SDW_CDNS_BRA_HDR]; 2370 + int dma_data_written; 2371 + u8 counter; 2372 + int ret; 2373 + 2374 + counter = CDNS_BPT_ROLLING_COUNTER_START; 2375 + 2376 + header[0] = 0; /* read command: BIT(1) cleared */ 2377 + header[0] |= GENMASK(7, 6); /* header is active */ 2378 + header[0] |= (dev_num << 2); 2379 + 2380 + while (data_size >= data_per_frame) { 2381 + header[1] = data_per_frame; 2382 + header[2] = start_register >> 24 & 0xFF; 2383 + header[3] = start_register >> 16 & 0xFF; 2384 + header[4] = start_register >> 8 & 0xFF; 2385 + header[5] = start_register >> 0 & 0xFF; 2386 + 2387 + ret = sdw_cdns_prepare_read_pd0_buffer(header, SDW_CDNS_BRA_HDR, p_dma_buffer, 2388 + dma_buffer_size, &dma_data_written, 2389 + counter); 2390 + if (ret < 0) 2391 + return ret; 2392 + 2393 + counter++; 2394 + 2395 + data_size -= data_per_frame; 2396 + 2397 + p_dma_buffer += dma_data_written; 2398 + dma_buffer_size -= dma_data_written; 2399 + total_dma_data_written += dma_data_written; 2400 + 2401 + start_register += data_per_frame; 2402 + } 2403 + 2404 + if (data_size) { 2405 + header[1] = data_size; 2406 + header[2] = start_register >> 24 & 0xFF; 2407 + header[3] = start_register >> 16 & 0xFF; 2408 + header[4] = start_register >> 8 & 0xFF; 2409 + header[5] = start_register >> 0 & 0xFF; 2410 + 2411 + ret = sdw_cdns_prepare_read_pd0_buffer(header, SDW_CDNS_BRA_HDR, p_dma_buffer, 2412 + dma_buffer_size, &dma_data_written, 2413 + counter); 2414 + if (ret < 0) 2415 + return ret; 2416 + 2417 + total_dma_data_written += dma_data_written; 2418 + } 2419 + 2420 + *dma_buffer_total_bytes = total_dma_data_written; 2421 + 2422 + return 0; 2423 + } 2424 + EXPORT_SYMBOL(sdw_cdns_prepare_read_dma_buffer); 2425 + 2426 + static int check_counter(u32 val, u8 counter) 2427 + { 2428 + u8 frame; 2429 + 2430 + frame = (val >> 24) & GENMASK(3, 0); 2431 + if (counter != frame) 2432 + return -EIO; 2433 + return 0; 2434 + } 2435 + 2436 + static int check_response(u32 val) 2437 + { 2438 + u8 response; 2439 + 2440 + response = (val >> 3) & GENMASK(1, 0); 2441 + if (response == 0) /* Ignored */ 2442 + return -ENODATA; 2443 + if (response != 1) /* ACK */ 2444 + return -EIO; 2445 + 2446 + return 0; 2447 + } 2448 + 2449 + static int check_frame_start(u32 header, u8 counter) 2450 + { 2451 + int ret; 2452 + 2453 + /* check frame_start marker */ 2454 + if (!(header & BIT(31))) 2455 + return -EIO; 2456 + 2457 + ret = check_counter(header, counter); 2458 + if (ret < 0) 2459 + return ret; 2460 + 2461 + return check_response(header); 2462 + } 2463 + 2464 + static int check_frame_end(u32 footer) 2465 + { 2466 + /* check frame_end marker */ 2467 + if (!(footer & BIT(30))) 2468 + return -EIO; 2469 + 2470 + return check_response(footer); 2471 + } 2472 + 2473 + int sdw_cdns_check_write_response(struct device *dev, u8 *dma_buffer, 2474 + int dma_buffer_size, int num_frames) 2475 + { 2476 + u32 *p_data; 2477 + int counter; 2478 + u32 header; 2479 + u32 footer; 2480 + int ret; 2481 + int i; 2482 + 2483 + /* paranoia check on buffer size */ 2484 + if (dma_buffer_size != num_frames * 8) 2485 + return -EINVAL; 2486 + 2487 + counter = CDNS_BPT_ROLLING_COUNTER_START; 2488 + p_data = (u32 *)dma_buffer; 2489 + 2490 + for (i = 0; i < num_frames; i++) { 2491 + header = *p_data++; 2492 + footer = *p_data++; 2493 + 2494 + ret = check_frame_start(header, counter); 2495 + if (ret < 0) { 2496 + dev_err(dev, "%s: bad frame %d/%d start header %x\n", 2497 + __func__, i, num_frames, header); 2498 + return ret; 2499 + } 2500 + 2501 + ret = check_frame_end(footer); 2502 + if (ret < 0) { 2503 + dev_err(dev, "%s: bad frame %d/%d end footer %x\n", 2504 + __func__, i, num_frames, footer); 2505 + return ret; 2506 + } 2507 + 2508 + counter++; 2509 + counter &= GENMASK(3, 0); 2510 + } 2511 + return 0; 2512 + } 2513 + EXPORT_SYMBOL(sdw_cdns_check_write_response); 2514 + 2515 + static u8 extract_read_data(u32 *data, int num_bytes, u8 *buffer) 2516 + { 2517 + u32 val; 2518 + int i; 2519 + u8 crc; 2520 + u8 b0; 2521 + u8 b1; 2522 + 2523 + crc = SDW_CRC8_SEED; 2524 + 2525 + /* process two bytes at a time */ 2526 + for (i = 0; i < num_bytes / 2; i++) { 2527 + val = *data++; 2528 + 2529 + b0 = val & 0xff; 2530 + b1 = (val >> 8) & 0xff; 2531 + 2532 + *buffer++ = b0; 2533 + crc = crc8(sdw_crc8_lookup_msb, &b0, 1, crc); 2534 + 2535 + *buffer++ = b1; 2536 + crc = crc8(sdw_crc8_lookup_msb, &b1, 1, crc); 2537 + } 2538 + /* handle remaining byte if it exists */ 2539 + if (num_bytes & 1) { 2540 + val = *data; 2541 + 2542 + b0 = val & 0xff; 2543 + 2544 + *buffer++ = b0; 2545 + crc = crc8(sdw_crc8_lookup_msb, &b0, 1, crc); 2546 + } 2547 + return crc; 2548 + } 2549 + 2550 + int sdw_cdns_check_read_response(struct device *dev, u8 *dma_buffer, int dma_buffer_size, 2551 + u8 *buffer, int buffer_size, int num_frames, int data_per_frame) 2552 + { 2553 + int total_num_bytes = 0; 2554 + u32 *p_data; 2555 + u8 *p_buf; 2556 + int counter; 2557 + u32 header; 2558 + u32 footer; 2559 + u8 expected_crc; 2560 + u8 crc; 2561 + int len; 2562 + int ret; 2563 + int i; 2564 + 2565 + counter = CDNS_BPT_ROLLING_COUNTER_START; 2566 + p_data = (u32 *)dma_buffer; 2567 + p_buf = buffer; 2568 + 2569 + for (i = 0; i < num_frames; i++) { 2570 + header = *p_data++; 2571 + 2572 + ret = check_frame_start(header, counter); 2573 + if (ret < 0) { 2574 + dev_err(dev, "%s: bad frame %d/%d start header %x\n", 2575 + __func__, i, num_frames, header); 2576 + return ret; 2577 + } 2578 + 2579 + len = data_per_frame; 2580 + if (total_num_bytes + data_per_frame > buffer_size) 2581 + len = buffer_size - total_num_bytes; 2582 + 2583 + crc = extract_read_data(p_data, len, p_buf); 2584 + 2585 + p_data += (len + 1) / 2; 2586 + expected_crc = *p_data++ & 0xff; 2587 + 2588 + if (crc != expected_crc) { 2589 + dev_err(dev, "%s: bad frame %d/%d crc %#x expected %#x\n", 2590 + __func__, i, num_frames, crc, expected_crc); 2591 + return -EIO; 2592 + } 2593 + 2594 + p_buf += len; 2595 + total_num_bytes += len; 2596 + 2597 + footer = *p_data++; 2598 + ret = check_frame_end(footer); 2599 + if (ret < 0) { 2600 + dev_err(dev, "%s: bad frame %d/%d end footer %x\n", 2601 + __func__, i, num_frames, footer); 2602 + return ret; 2603 + } 2604 + 2605 + counter++; 2606 + counter &= GENMASK(3, 0); 2607 + } 2608 + return 0; 2609 + } 2610 + EXPORT_SYMBOL(sdw_cdns_check_read_response); 1979 2611 1980 2612 MODULE_LICENSE("Dual BSD/GPL"); 1981 2613 MODULE_DESCRIPTION("Cadence Soundwire Library");
+20
drivers/soundwire/cadence_master.h
··· 208 208 void sdw_cdns_config_update(struct sdw_cdns *cdns); 209 209 int sdw_cdns_config_update_set_wait(struct sdw_cdns *cdns); 210 210 211 + /* SoundWire BPT/BRA helpers to format data */ 212 + int sdw_cdns_bpt_find_buffer_sizes(int command, /* 0: write, 1: read */ 213 + int row, int col, unsigned int data_bytes, 214 + unsigned int requested_bytes_per_frame, 215 + unsigned int *data_per_frame, unsigned int *pdi0_buffer_size, 216 + unsigned int *pdi1_buffer_size, unsigned int *num_frames); 217 + 218 + int sdw_cdns_prepare_write_dma_buffer(u8 dev_num, u32 start_register, u8 *data, int data_size, 219 + int data_per_frame, u8 *dma_buffer, int dma_buffer_size, 220 + int *dma_buffer_total_bytes); 221 + 222 + int sdw_cdns_prepare_read_dma_buffer(u8 dev_num, u32 start_register, int data_size, 223 + int data_per_frame, u8 *dma_buffer, int dma_buffer_size, 224 + int *dma_buffer_total_bytes); 225 + 226 + int sdw_cdns_check_write_response(struct device *dev, u8 *dma_buffer, 227 + int dma_buffer_size, int num_frames); 228 + 229 + int sdw_cdns_check_read_response(struct device *dev, u8 *dma_buffer, int dma_buffer_size, 230 + u8 *buffer, int buffer_size, int num_frames, int data_per_frame); 211 231 #endif /* __SDW_CADENCE_H */