1 /* 2 * Perform SPI communication using the JZ4780 SPI peripheral. 3 * 4 * Copyright (C) 2023 Paul Boddie <paul@boddie.org.uk> 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License as 8 * published by the Free Software Foundation; either version 2 of 9 * the License, or (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 * Boston, MA 02110-1301, USA 20 */ 21 22 #include <l4/devices/spi-jz4780.h> 23 #include <l4/devices/dma.h> 24 #include <l4/sys/err.h> 25 #include <string.h> 26 27 28 29 /* Register definitions. */ 30 31 enum Regs 32 { 33 Ssi_data = 0x00, // SSIDR 34 Ssi_control0 = 0x04, // SSICR0 35 Ssi_control1 = 0x08, // SSICR1 36 Ssi_status = 0x0c, // SSISR 37 Ssi_interval_time = 0x10, // SSIITR 38 Ssi_char_per_frame = 0x14, // SSIICR 39 Ssi_clock = 0x18, // SSICGR 40 Ssi_recv_counter = 0x1c, // SSIRCNT 41 42 /* Register block offset. */ 43 44 Ssi_block_offset = 0x1000, 45 }; 46 47 enum Ssi_data_bits : unsigned 48 { 49 Ssi_data_gpc = 0x1000, 50 }; 51 52 enum Ssi_control0_bits : unsigned 53 { 54 Ssi_trans_endian_mask = 0xc0000, 55 Ssi_trans_endian_msbyte_msbit = 0x00000, 56 Ssi_trans_endian_msbyte_lsbit = 0x40000, 57 Ssi_trans_endian_lsbyte_lsbit = 0x80000, 58 Ssi_trans_endian_lsbyte_msbit = 0xc0000, 59 60 Ssi_recv_endian_mask = 0x30000, 61 Ssi_recv_endian_msbyte_msbit = 0x00000, 62 Ssi_recv_endian_msbyte_lsbit = 0x10000, 63 Ssi_recv_endian_lsbyte_lsbit = 0x20000, 64 Ssi_recv_endian_lsbyte_msbit = 0x30000, 65 66 Ssi_enable = 0x08000, 67 Ssi_enable_trans_half_empty = 0x04000, 68 Ssi_enable_recv_half_full = 0x02000, 69 Ssi_enable_trans_error = 0x01000, 70 Ssi_enable_recv_error = 0x00800, 71 Ssi_loop = 0x00400, 72 Ssi_recv_finish_control = 0x00200, 73 Ssi_recv_finished = 0x00100, 74 Ssi_enable_auto_clear_underrun = 0x00080, 75 Ssi_select_pin_is_ce2 = 0x00040, 76 Ssi_use_recv_count = 0x00010, 77 Ssi_old_fifo_empty_mode = 0x00008, 78 Ssi_trans_flush = 0x00004, 79 Ssi_recv_flush = 0x00002, 80 Ssi_disable_recv = 0x00001, 81 }; 82 83 enum Ssi_control1_bits : unsigned 84 { 85 Ssi_active_mask = 0xc0000000, 86 Ssi_active_ce_low = 0x00000000, 87 Ssi_active_ce_high = 0x40000000, 88 Ssi_active_ce2_low = 0x00000000, 89 Ssi_active_ce2_high = 0x80000000, 90 91 Ssi_clock_start_delay_mask = 0x30000000, 92 Ssi_clock_start_delay_default = 0x00000000, 93 Ssi_clock_start_delay_plus_1 = 0x10000000, 94 Ssi_clock_start_delay_plus_2 = 0x20000000, 95 Ssi_clock_start_delay_plus_3 = 0x30000000, 96 97 Ssi_clock_stop_delay_mask = 0x0c000000, 98 Ssi_clock_stop_delay_default = 0x00000000, 99 Ssi_clock_stop_delay_plus_1 = 0x04000000, 100 Ssi_clock_stop_delay_plus_2 = 0x08000000, 101 Ssi_clock_stop_delay_plus_3 = 0x0c000000, 102 103 Ssi_interval_assert_ce_or_ce2 = 0x01000000, 104 Ssi_trans_empty_unfinished = 0x00800000, 105 106 Ssi_format_mask = 0x00300000, 107 Ssi_format_spi = 0x00000000, 108 Ssi_format_ssp = 0x00100000, 109 Ssi_format_microwire1 = 0x00200000, 110 Ssi_format_microwire2 = 0x00300000, 111 112 Ssi_trans_threshold_mask = 0x000f0000, 113 Ssi_command_length_mask = 0x0000f000, 114 Ssi_recv_threshold_mask = 0x00000f00, 115 Ssi_char_length_mask = 0x000000f8, 116 117 Spi_clock_assert_sample = 0x00000000, // phase #0 118 Spi_clock_assert_drive = 0x00000002, // phase #1 119 Spi_clock_idle_low_level = 0x00000000, // polarity #0 120 Spi_clock_idle_high_level = 0x00000001, // polarity #1 121 }; 122 123 enum Ssi_control1_shifts : unsigned 124 { 125 Ssi_trans_threshold_shift = 16, 126 Ssi_command_length_shift = 12, 127 Ssi_recv_threshold_shift = 8, 128 Ssi_char_length_shift = 3, 129 }; 130 131 enum Ssi_control1_limits : unsigned 132 { 133 Ssi_trans_threshold_limit = 15, 134 Ssi_command_length_limit = 15, 135 Ssi_recv_threshold_limit = 15, 136 Ssi_char_length_limit = 30, 137 }; 138 139 enum Ssi_status_bits : unsigned 140 { 141 Ssi_trans_char_count_mask = 0x00ff0000, 142 Ssi_recv_char_count_mask = 0x0000ff00, 143 Ssi_trans_ended = 0x00000080, 144 Ssi_trans_busy = 0x00000040, 145 Ssi_trans_fifo_full = 0x00000020, 146 Ssi_recv_fifo_empty = 0x00000010, 147 Ssi_trans_fifo_half_empty = 0x00000008, 148 Ssi_recv_fifo_half_full = 0x00000004, 149 Ssi_trans_underrun = 0x00000002, 150 Ssi_recv_overrun = 0x00000001, 151 }; 152 153 enum Ssi_status_shifts : unsigned 154 { 155 Ssi_trans_char_count_shift = 16, 156 Ssi_recv_char_count_shift = 8, 157 }; 158 159 enum Ssi_status_limits : unsigned 160 { 161 Ssi_trans_char_count_limit = 0xff, 162 Ssi_recv_char_count_limit = 0xff, 163 }; 164 165 enum Ssi_interval_time_bits : unsigned 166 { 167 Ssi_interval_clock_mask = 0x8000, 168 Ssi_interval_clock_bit_clock = 0x0000, 169 Ssi_interval_clock_32k_clock = 0x8000, 170 Ssi_interval_time_mask = 0x3fff, 171 }; 172 173 enum Ssi_char_per_frame_bits : unsigned 174 { 175 Ssi_char_per_frame_mask = 0x7, 176 }; 177 178 enum Ssi_clock_bits : unsigned 179 { 180 Ssi_clock_frequency_mask = 0xff, 181 }; 182 183 enum Ssi_recv_counter_bits : unsigned 184 { 185 Ssi_recv_counter_mask = 0xffff, 186 }; 187 188 189 190 /* Initialise a channel. */ 191 192 Spi_jz4780_channel::Spi_jz4780_channel(l4_addr_t spi_start, l4_addr_t start, 193 enum Clock_identifiers clock, 194 Cpm_jz4780_chip *cpm, 195 Dma_jz4780_channel *dma, 196 enum Dma_jz4780_request_type request_type, 197 uint64_t frequency) 198 : _spi_start(spi_start), _clock(clock), _cpm(cpm), _dma(dma), 199 _request_type(request_type), _frequency(frequency) 200 { 201 _regs = new Hw::Mmio_register_block<32>(start); 202 _cpm->start_clock(clock); 203 204 /* Disable the channel while configuring: send MSB first, big endian wire 205 representation. Disable reception. */ 206 207 _regs[Ssi_control0] = Ssi_trans_endian_msbyte_msbit | 208 Ssi_select_pin_is_ce2 | 209 Ssi_disable_recv; 210 211 /* Set default transfer properties. */ 212 213 configure_transfer(8); 214 215 /* Select "normal" mode. */ 216 217 _regs[Ssi_interval_time] = 0; 218 219 /* Limit the frequency to half that of the device clock. */ 220 221 if (_frequency >= _cpm->get_frequency(_clock)) 222 _frequency = _cpm->get_frequency(_clock) / 2; 223 224 /* SSI_CLK = DEV_CLK / (2 * (divider + 1)) */ 225 226 uint32_t divider = _cpm->get_frequency(_clock) / (_frequency * 2) - 1; 227 228 _regs[Ssi_clock] = divider < Ssi_clock_frequency_mask ? divider : Ssi_clock_frequency_mask; 229 230 /* Enable the channel. */ 231 232 _regs[Ssi_control0] = _regs[Ssi_control0] | Ssi_enable; 233 } 234 235 /* NOTE: More transfer characteristics should be configurable. */ 236 237 void Spi_jz4780_channel::configure_transfer(uint8_t char_size) 238 { 239 uint32_t char_length; 240 241 if (char_size < 2) 242 char_length = 0; 243 else 244 { 245 char_length = char_size - 2; 246 247 if (char_size > Ssi_char_length_limit) 248 char_length = Ssi_char_length_limit; 249 } 250 251 /* Clear the status. */ 252 253 _regs[Ssi_control0] = _regs[Ssi_control0] | Ssi_trans_flush | Ssi_recv_flush; 254 _regs[Ssi_status] = 0; 255 256 /* Indicate the desired character size. 257 258 Use active low device selection, SPI format with active low clock, with 259 data driven on the falling (asserted) clock and sampled on the rising 260 clock 261 262 The unfinished flag prevents the transaction from finishing if the FIFO is 263 empty. It is not used here since it appears to prevent any meaningful 264 testing of the busy and end flags. */ 265 266 _regs[Ssi_control1] = (char_length << Ssi_char_length_shift) | 267 ((Ssi_trans_threshold_limit / 2) << Ssi_trans_threshold_shift) | 268 Ssi_format_spi | Ssi_active_ce2_low | 269 Spi_clock_assert_drive | Spi_clock_idle_high_level; 270 } 271 272 /* Transfer the given number of bytes from a buffer using the given unit size in 273 bytes and character size in bits. */ 274 275 uint32_t 276 Spi_jz4780_channel::send(uint32_t bytes, const uint8_t data[], uint8_t unit_size, 277 uint8_t char_size) 278 { 279 configure_transfer(char_size); 280 281 uint32_t transferred; 282 uint32_t char_mask = (1 << char_size) - 1; 283 284 for (transferred = 0; transferred < bytes; transferred += unit_size) 285 { 286 uint32_t value = 0; 287 288 for (uint8_t byte = 0; byte < unit_size; byte++) 289 value = (value << 8) | data[transferred + byte]; 290 291 /* Relocate any command bit to bit 16 for byte characters. */ 292 293 uint32_t command = (char_size < 16) && (value & (1 << char_size)) ? (1 << 16) : 0; 294 295 /* Combine the significant portion of the character with the command. */ 296 297 value = (value & char_mask) | command; 298 _regs[Ssi_data] = value; 299 } 300 301 /* Wait for the busy condition to clear or for a limited period. */ 302 303 for (unsigned int i = 0; i < (1 << 20) && (_regs[Ssi_status] & Ssi_trans_busy); i++); 304 305 return transferred; 306 } 307 308 /* Transfer the given number of bytes from a DMA region using the given 309 unit size in bytes and character size in bits. */ 310 311 uint32_t Spi_jz4780_channel::transfer(l4re_dma_space_dma_addr_t paddr, 312 uint32_t count, uint8_t unit_size, 313 uint8_t char_size) 314 { 315 configure_transfer(char_size); 316 317 uint32_t transferred = 0; 318 uint32_t unit_count = count / unit_size; 319 uint32_t to_transfer = _dma->transfer(paddr, _spi_start + Ssi_data, 320 unit_count, true, false, 321 unit_size, unit_size, unit_size, 322 _request_type); 323 324 if (to_transfer) 325 transferred = to_transfer ? (unit_count - _dma->wait()) * unit_size : 0; 326 327 /* Wait for the busy condition to clear or for a limited period. */ 328 329 for (unsigned int i = 0; i < (1 << 20) && (_regs[Ssi_status] & Ssi_trans_busy); i++); 330 331 return transferred; 332 } 333 334 335 336 /* Initialise the peripheral abstraction. */ 337 338 Spi_jz4780_chip::Spi_jz4780_chip(l4_addr_t spi_start, l4_addr_t start, 339 l4_addr_t end, Cpm_jz4780_chip *cpm) 340 : _spi_start(spi_start), _start(start), _end(end), _cpm(cpm) 341 { 342 } 343 344 Spi_jz4780_channel * 345 Spi_jz4780_chip::get_channel(uint8_t channel, Dma_jz4780_channel *dma, 346 uint64_t frequency) 347 { 348 // NOTE: Only sending is supported. 349 350 enum Dma_jz4780_request_type request_types[] = {Dma_request_ssi0_out, Dma_request_ssi1_out}; 351 enum Clock_identifiers clocks[] = {Clock_ssi0, Clock_ssi1}; 352 353 if (channel < 2) 354 return new Spi_jz4780_channel(_spi_start + channel * Ssi_block_offset, 355 _start + channel * Ssi_block_offset, 356 clocks[channel], 357 _cpm, dma, request_types[channel], frequency); 358 else 359 throw -L4_EINVAL; 360 } 361 362 363 364 /* C language interface. */ 365 366 void *jz4780_spi_init(l4_addr_t spi_start, l4_addr_t start, l4_addr_t end, void *cpm) 367 { 368 return new Spi_jz4780_chip(spi_start, start, end, static_cast<Cpm_jz4780_chip *>(cpm)); 369 } 370 371 void *jz4780_spi_get_channel(void *spi, uint8_t channel, void *dma, uint64_t frequency) 372 { 373 return static_cast<Spi_jz4780_chip *>(spi)->get_channel(channel, 374 static_cast<Dma_jz4780_channel *>(dma), frequency); 375 } 376 377 uint32_t jz4780_spi_send(void *channel, uint32_t bytes, const uint8_t data[], 378 uint8_t unit_size, uint8_t char_size) 379 { 380 return static_cast<Spi_jz4780_channel *>(channel)->send(bytes, data, unit_size, char_size); 381 } 382 383 uint32_t jz4780_spi_transfer(void *channel, l4re_dma_space_dma_addr_t paddr, 384 uint32_t count, uint8_t unit_size, uint8_t char_size) 385 { 386 return static_cast<Spi_jz4780_channel *>(channel)->transfer(paddr, count, unit_size, char_size); 387 }