1 /* 2 * DMA support for the JZ4780. 3 * NOTE: This should be combined with the X1600 support. 4 * 5 * Copyright (C) 2021, 2023 Paul Boddie <paul@boddie.org.uk> 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License as 9 * published by the Free Software Foundation; either version 2 of 10 * the License, or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, 20 * Boston, MA 02110-1301, USA 21 */ 22 23 #include <l4/devices/dma-jz4780.h> 24 #include <l4/devices/hw_mmio_register_block.h> 25 26 #include <l4/sys/icu.h> 27 #include <l4/sys/ipc.h> 28 #include <l4/sys/irq.h> 29 #include <l4/util/util.h> 30 31 #include <stdio.h> 32 33 34 35 enum Global_regs 36 { 37 Dma_control = 0x1000, // DMAC 38 Dma_irq_pending = 0x1004, // DIRQP 39 }; 40 41 enum Channel_regs 42 { 43 Dma_source = 0x00, // DSA 44 Dma_destination = 0x04, // DTA 45 Dma_transfer_count = 0x08, // DTC 46 Dma_request_source = 0x0c, // DRT 47 Dma_control_status = 0x10, // DCS 48 Dma_command = 0x14, // DCM 49 Dma_descriptor_address = 0x18, // DDA 50 Dma_stride = 0x1c, // DSD 51 }; 52 53 enum Dma_control_bits : unsigned 54 { 55 Dma_fast_msc_transfer = 0x80000000, // FMSC 56 Dma_fast_ssi_transfer = 0x40000000, // FSSI 57 Dma_fast_tssi_transfer = 0x20000000, // FTSSI 58 Dma_fast_uart_transfer = 0x10000000, // FUART 59 Dma_fast_aic_transfer = 0x08000000, // FAIC 60 61 Dma_intc_irq_channel_mask = 0x003e0000, // INTCC 62 Dma_intc_irq_channel_bind = 0x00010000, // INTCE 63 64 Dma_control_trans_halted = 0x00000008, // HLT 65 Dma_control_address_error = 0x00000004, // AR 66 Dma_control_special_ch01 = 0x00000002, // CH01 67 Dma_control_enable = 0x00000001, // DMAE 68 }; 69 70 enum Dma_transfer_count_bits : unsigned 71 { 72 Dma_transfer_count_mask = 0x00ffffff, 73 }; 74 75 enum Dma_request_source_bits : unsigned 76 { 77 Dma_request_type_mask = 0x0000003f, 78 }; 79 80 enum Dma_control_status_bits : unsigned 81 { 82 Dma_no_descriptor_transfer = 0x80000000, 83 Dma_8word_descriptor = 0x40000000, 84 Dma_copy_offset_mask = 0x0000ff00, 85 Dma_address_error = 0x00000010, 86 Dma_trans_completed = 0x00000008, 87 Dma_trans_halted = 0x00000004, 88 Dma_channel_enable = 0x00000001, 89 90 Dma_copy_offset_shift = 8, 91 }; 92 93 enum Dma_command_bits : unsigned 94 { 95 Dma_special_source_mask = 0x0c000000, 96 Dma_special_source_tcsm = 0x00000000, 97 Dma_special_source_bch_nemc = 0x04000000, 98 Dma_special_source_reserved_ddr = 0x08000000, 99 100 Dma_special_destination_mask = 0x03000000, 101 Dma_special_destination_tcsm = 0x00000000, 102 Dma_special_destination_bch_nemc = 0x01000000, 103 Dma_special_destination_reserved_ddr = 0x02000000, 104 105 Dma_source_address_increment = 0x00800000, 106 Dma_source_address_no_increment = 0x00000000, 107 Dma_destination_address_increment = 0x00400000, 108 Dma_destination_address_no_increment = 0x00000000, 109 110 Dma_recommended_data_unit_size_mask = 0x000f0000, 111 Dma_source_port_width_mask = 0x0000c000, 112 Dma_destination_port_width_mask = 0x00003000, 113 Dma_transfer_unit_size_mask = 0x00000f00, 114 115 Dma_trans_unit_size_32_bit = 0x00000000, 116 Dma_trans_unit_size_8_bit = 0x00000100, 117 Dma_trans_unit_size_16_bit = 0x00000200, 118 Dma_trans_unit_size_16_byte = 0x00000300, 119 Dma_trans_unit_size_32_byte = 0x00000400, 120 Dma_trans_unit_size_64_byte = 0x00000500, 121 Dma_trans_unit_size_128_byte = 0x00000600, 122 Dma_trans_unit_size_autonomous = 0x00000700, 123 124 Dma_stride_enable = 0x00000004, 125 Dma_transfer_irq_enable = 0x00000002, 126 Dma_descriptor_link_enable = 0x00000001, 127 128 Dma_recommended_data_unit_size_shift = 16, 129 Dma_source_port_width_shift = 14, 130 Dma_destination_port_width_shift = 12, 131 Dma_transfer_unit_size_shift = 8, 132 }; 133 134 enum Dma_port_width_values : unsigned 135 { 136 Dma_port_width_32_bit = 0, 137 Dma_port_width_8_bit = 1, 138 Dma_port_width_16_bit = 2, 139 }; 140 141 142 143 // Initialise a channel. 144 145 Dma_jz4780_channel::Dma_jz4780_channel(Dma_jz4780_chip *chip, uint8_t channel, 146 l4_addr_t start, l4_cap_idx_t irq) 147 : _chip(chip), _channel(channel), _irq(irq) 148 { 149 _regs = new Hw::Mmio_register_block<32>(start); 150 151 // Initialise the transfer count. 152 153 _regs[Dma_transfer_count] = 0; 154 } 155 156 // Return the closest interval length greater than or equal to the number of 157 // units given encoded in the request detection interval length field of the 158 // control/status register. 159 160 uint32_t 161 Dma_jz4780_channel::encode_req_detect_int_length(uint8_t units) 162 { 163 static uint8_t lengths[] = {0, 1, 2, 3, 4, 8, 16, 32, 64, 128}; 164 int i; 165 166 if (!units) 167 return 0; 168 169 for (i = 0; i <= 9; i++) 170 { 171 if (lengths[i] >= units) 172 break; 173 } 174 175 return i << Dma_recommended_data_unit_size_shift; 176 } 177 178 // Encode the appropriate source port width for the given request type. 179 180 uint32_t 181 Dma_jz4780_channel::encode_source_port_width(uint8_t width) 182 { 183 switch (width) 184 { 185 case 1: 186 return Dma_port_width_8_bit << Dma_source_port_width_shift; 187 188 case 2: 189 return Dma_port_width_16_bit << Dma_source_port_width_shift; 190 191 default: 192 return Dma_port_width_32_bit << Dma_source_port_width_shift; 193 } 194 } 195 196 // Encode the appropriate destination port width for the given request type. 197 198 uint32_t 199 Dma_jz4780_channel::encode_destination_port_width(uint8_t width) 200 { 201 switch (width) 202 { 203 case 1: 204 return Dma_port_width_8_bit << Dma_destination_port_width_shift; 205 206 case 2: 207 return Dma_port_width_16_bit << Dma_destination_port_width_shift; 208 209 default: 210 return Dma_port_width_32_bit << Dma_destination_port_width_shift; 211 } 212 } 213 214 // Encode the transfer unit size. 215 // NOTE: This does not handle the external case. 216 217 uint32_t 218 Dma_jz4780_channel::encode_transfer_unit_size(uint8_t size) 219 { 220 switch (size) 221 { 222 case 0: 223 return Dma_trans_unit_size_autonomous; 224 225 case 1: 226 return Dma_trans_unit_size_8_bit; 227 228 case 2: 229 return Dma_trans_unit_size_16_bit; 230 231 case 16: 232 return Dma_trans_unit_size_16_byte; 233 234 case 32: 235 return Dma_trans_unit_size_32_byte; 236 237 case 64: 238 return Dma_trans_unit_size_64_byte; 239 240 case 128: 241 return Dma_trans_unit_size_128_byte; 242 243 default: 244 return Dma_trans_unit_size_32_bit; 245 } 246 } 247 248 // Transfer data between memory locations. 249 250 unsigned int 251 Dma_jz4780_channel::transfer(uint32_t source, uint32_t destination, 252 unsigned int count, 253 bool source_increment, bool destination_increment, 254 uint8_t source_width, uint8_t destination_width, 255 uint8_t transfer_unit_size, 256 enum Dma_jz4780_request_type type) 257 { 258 printf("transfer:%s%s%s%s\n", error() ? " error" : "", 259 halted() ? " halted" : "", 260 completed() ? " completed" : "", 261 _regs[Dma_transfer_count] ? " count" : ""); 262 263 // Ensure an absence of address error and halt conditions globally and in this channel. 264 265 if (error() || halted()) 266 return 0; 267 268 // Ensure an absence of transaction completed and zero transfer count for this channel. 269 270 if (completed() || _regs[Dma_transfer_count]) 271 return 0; 272 273 // Disable the channel. 274 275 _regs[Dma_control_status] = _regs[Dma_control_status] & ~Dma_channel_enable; 276 277 // Set addresses. 278 279 _regs[Dma_source] = source; 280 _regs[Dma_destination] = destination; 281 282 // Set transfer count to the number of units. 283 284 unsigned int units = count < Dma_transfer_count_mask ? count : Dma_transfer_count_mask; 285 286 _regs[Dma_transfer_count] = units; 287 288 // Set auto-request for memory-to-memory transfers. Otherwise, set the 289 // indicated request type. 290 291 _regs[Dma_request_source] = type; 292 293 // For a descriptor, the actual fields would be populated instead of the 294 // command register, descriptor transfer would be indicated in the control/ 295 // status register along with the appropriate descriptor size indicator. 296 297 /* NOTE: To be considered... 298 * request detection interval length (for autonomous mode) 299 */ 300 301 _regs[Dma_command] = (source_increment ? Dma_source_address_increment : Dma_source_address_no_increment) | 302 (destination_increment ? Dma_destination_address_increment : Dma_destination_address_no_increment) | 303 encode_source_port_width(source_width) | 304 encode_destination_port_width(destination_width) | 305 encode_transfer_unit_size(transfer_unit_size) | 306 Dma_transfer_irq_enable; 307 308 // For a descriptor, the descriptor address would be set and the doorbell 309 // register field for the channel set. 310 311 // Enable the channel (and peripheral). 312 313 _regs[Dma_control_status] = Dma_no_descriptor_transfer | 314 Dma_channel_enable; 315 316 // Return the number of units to transfer. 317 318 return units; 319 } 320 321 unsigned int 322 Dma_jz4780_channel::wait() 323 { 324 // An interrupt will occur upon completion, the completion flag will be set 325 // and the transfer count will be zero. 326 327 unsigned int remaining = 0; 328 329 do 330 { 331 if (!wait_for_irq(1000000)) 332 printf("status = %x\n", (uint32_t) _regs[Dma_control_status]); 333 else 334 { 335 printf("status = %x\n", (uint32_t) _regs[Dma_control_status]); 336 remaining = _regs[Dma_transfer_count]; 337 ack_irq(); 338 break; 339 } 340 } 341 while (!error() && !halted() && !completed()); 342 343 // Reset the channel status. 344 345 _regs[Dma_control_status] = _regs[Dma_control_status] & ~(Dma_channel_enable | 346 Dma_trans_completed | Dma_address_error | 347 Dma_trans_halted); 348 _regs[Dma_transfer_count] = 0; 349 350 // Return the number of remaining units. 351 352 return remaining; 353 } 354 355 // Wait indefinitely for an interrupt request, returning true if one was delivered. 356 357 bool 358 Dma_jz4780_channel::wait_for_irq() 359 { 360 return !l4_error(l4_irq_receive(_irq, L4_IPC_NEVER)) && _chip->have_interrupt(_channel); 361 } 362 363 // Wait up to the given timeout (in microseconds) for an interrupt request, 364 // returning true if one was delivered. 365 366 bool 367 Dma_jz4780_channel::wait_for_irq(unsigned int timeout) 368 { 369 return !l4_error(l4_irq_receive(_irq, l4_timeout(L4_IPC_TIMEOUT_NEVER, l4util_micros2l4to(timeout)))) && _chip->have_interrupt(_channel); 370 } 371 372 // Acknowledge an interrupt condition. 373 374 void 375 Dma_jz4780_channel::ack_irq() 376 { 377 _chip->ack_irq(_channel); 378 } 379 380 // Return whether a transfer has completed. 381 382 bool 383 Dma_jz4780_channel::completed() 384 { 385 return _regs[Dma_control_status] & Dma_trans_completed ? true : false; 386 } 387 388 // Return whether an address error condition has arisen. 389 390 bool 391 Dma_jz4780_channel::error() 392 { 393 return _chip->error() || (_regs[Dma_control_status] & Dma_address_error ? true : false); 394 } 395 396 // Return whether a transfer has halted. 397 398 bool 399 Dma_jz4780_channel::halted() 400 { 401 return _chip->halted() || (_regs[Dma_control_status] & Dma_trans_halted ? true : false); 402 } 403 404 405 406 // Initialise the I2C controller. 407 408 Dma_jz4780_chip::Dma_jz4780_chip(l4_addr_t start, l4_addr_t end, 409 Cpm_jz4780_chip *cpm) 410 : _start(start), _end(end), _cpm(cpm) 411 { 412 _regs = new Hw::Mmio_register_block<32>(start); 413 } 414 415 // Enable the peripheral. 416 417 void 418 Dma_jz4780_chip::enable() 419 { 420 // Make sure that the DMA clock is available. 421 422 _cpm->start_clock(Clock_dma); 423 424 _regs[Dma_control] = Dma_control_enable; 425 while (!(_regs[Dma_control] & Dma_control_enable)); 426 } 427 428 // Disable the channel. 429 430 void 431 Dma_jz4780_chip::disable() 432 { 433 _regs[Dma_control] = 0; 434 while (_regs[Dma_control] & Dma_control_enable); 435 } 436 437 // Obtain a channel object. 438 439 Dma_jz4780_channel * 440 Dma_jz4780_chip::get_channel(uint8_t channel, l4_cap_idx_t irq) 441 { 442 if (channel < 32) 443 return new Dma_jz4780_channel(this, channel, _start + 0x20 * channel, irq); 444 else 445 throw -L4_EINVAL; 446 } 447 448 // Return whether an interrupt is pending on the given channel. 449 450 bool 451 Dma_jz4780_chip::have_interrupt(uint8_t channel) 452 { 453 return _regs[Dma_irq_pending] & (1 << channel) ? true : false; 454 } 455 456 // Acknowledge an interrupt condition on the given channel. 457 458 void 459 Dma_jz4780_chip::ack_irq(uint8_t channel) 460 { 461 _regs[Dma_irq_pending] = _regs[Dma_irq_pending] & ~(1 << channel); 462 } 463 464 // Return whether an address error condition has arisen. 465 466 bool 467 Dma_jz4780_chip::error() 468 { 469 return _regs[Dma_control] & Dma_control_address_error ? true : false; 470 } 471 472 // Return whether a transfer has halted. 473 474 bool 475 Dma_jz4780_chip::halted() 476 { 477 return _regs[Dma_control] & Dma_control_trans_halted ? true : false; 478 } 479 480 481 482 // C language interface functions. 483 484 void *jz4780_dma_init(l4_addr_t start, l4_addr_t end, void *cpm) 485 { 486 return (void *) new Dma_jz4780_chip(start, end, static_cast<Cpm_jz4780_chip *>(cpm)); 487 } 488 489 void jz4780_dma_disable(void *dma_chip) 490 { 491 static_cast<Dma_jz4780_chip *>(dma_chip)->disable(); 492 } 493 494 void jz4780_dma_enable(void *dma_chip) 495 { 496 static_cast<Dma_jz4780_chip *>(dma_chip)->enable(); 497 } 498 499 void *jz4780_dma_get_channel(void *dma, uint8_t channel, l4_cap_idx_t irq) 500 { 501 return static_cast<Dma_jz4780_chip *>(dma)->get_channel(channel, irq); 502 } 503 504 unsigned int jz4780_dma_transfer(void *dma_channel, 505 uint32_t source, uint32_t destination, 506 unsigned int count, 507 int source_increment, int destination_increment, 508 uint8_t source_width, uint8_t destination_width, 509 uint8_t transfer_unit_size, 510 enum Dma_jz4780_request_type type) 511 { 512 return static_cast<Dma_jz4780_channel *>(dma_channel)->transfer(source, 513 destination, count, source_increment, destination_increment, source_width, 514 destination_width, transfer_unit_size, type); 515 } 516 517 unsigned int jz4780_dma_wait(void *dma_channel) 518 { 519 return static_cast<Dma_jz4780_channel *>(dma_channel)->wait(); 520 }