1 /******************************************************************************* 2 * Copyright 2019-2020 Microchip FPGA Embedded Systems Solutions. 3 * 4 * SPDX-License-Identifier: MIT 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to 8 * deal in the Software without restriction, including without limitation the 9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10 * sell copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22 * IN THE SOFTWARE. 23 * 24 * PolarFire SoC Microprocessor subsystem PDMA bare metal software driver public 25 * APIs. 26 */ 27 28 /*=========================================================================*//** 29 @mainpage PolarFire SoC MSS PDMA Bare Metal Driver. 30 31 ============================================================================== 32 Introduction 33 ============================================================================== 34 The PolarFire SoC Microprocessor Subsystem (MSS) includes the MSS PDMA 35 peripherals for autonomous data transfers. The MSS PDMA has memory-mapped 36 control registers accessed over a TileLink slave interface to allow software 37 to set up DMA transfers, and has a TileLink bus master port into the TileLink 38 bus fabric to allow it to rapidly copy data between two locations in memory. 39 The MSS PDMA can support multiple independent simultaneous DMA transfers 40 using different PDMA channels and can generate PLIC interrupts on either a 41 transfer has completed, or when a transfer error has occurred. 42 43 ============================================================================== 44 Hardware Flow Dependencies 45 ============================================================================== 46 The configuration of all features of the MSS PDMA driver is covered by this 47 driver. There are no dependencies on the hardware flow when configuring MSS 48 PDMA. 49 The source and destination of the DMA transaction must be enabled, either in 50 the hardware or by your application program. The source and destination 51 addresses must be located at valid addresses in the PolarFire SoC MSS memory 52 map and must be appropriate to the configuration that you specify the PDMA 53 channel. 54 The base address, register addresses, and interrupt numbers associated with 55 MSS PDMA block are defined in the mpfs hal as constants. User must ensure that 56 the latest mpfs hal is included in the example project. 57 58 ============================================================================== 59 Theory of Operation 60 ============================================================================== 61 The PDMA driver function are grouped into the following categories: 62 - Initialization 63 - Configuration 64 - Transfer Control 65 - Interrupt Control 66 67 -------------------------------- 68 Initialization 69 -------------------------------- 70 The PolarFire SoC MSS PDMA driver is initialized through the call to the 71 MSS_PDMA_init() function. The MSS_PDMA_init() function must be called before 72 any other MSS PDMA driver functions. 73 74 -------------------------------- 75 Configuration 76 -------------------------------- 77 Each PDMA channel is configured through the call to MSS_PDMA_setup_transfer() 78 function. Configuration includes : 79 - The PDMA channel for transaction. 80 - Source and destination addresses. 81 - The transfer sizes. 82 - Repeat the transfer 83 - Ordering requirements. 84 - Set / Clear the interrupt for the transfer 85 86 The PolarFire SoC MSS PDMA has four independent DMA channels which operate 87 concurrently to support multiple simultaneous transfers. Each channel has an 88 independent set of registers and interrupts. The PDMA channels can be 89 configured through the call to MSS_PDMA_setup_transfer() function. Apart from 90 selecting the channel the MSS_PDMA_setup_transfer() function will also setup 91 the transfer size, source and destination addresses. 92 MSS_PDMA_setup_transfer() function will also configure the repeat and force 93 order requirements as the PoalrFire SoC MSS PDMA supports multiple 94 simultaneous transfers. 95 The PDMA has two interrupts per channel which are used to signal when either 96 a transfer has completed or when a transfer error has occurred. These 97 interrupts are enabled by the application software and are set / cleared 98 by MSS_PDMA_setup_transfer() function. 99 100 -------------------------------- 101 Transfer Control 102 -------------------------------- 103 The PDMA transfers can be initiated by a call to the MSS_PDMA_start_transfer() 104 function after a PDMA channel has been configured. The 105 MSS_PDMA_start_transfer() function will write the config register in PDMA 106 memory map. The write_size and read_size buffers are used to determine the 107 size and alignment of individual PDMA transactions as a single PDMA transfers 108 may require multiple transactions. 109 The configuration of the currently selected PDMA channel can be read by 110 calling the MSS_PDMA_get_active_transfer_type() function. 111 112 -------------------------------- 113 Interrupt Control 114 -------------------------------- 115 The PDMA has two interrupts per channel which are used to signal either a 116 successful completion og the transfer, a transfer error. These interrupts are 117 enabled by the application software by a call to MSS_PDMA_setup_transfer() 118 function. The MSS_PDMA_get_transfer_complete_status() function will indicate 119 the DMA transfer success status for selected DMA channel. The 120 MSS_PDMA_get_transfer_error_status() function will indicate the DMA transfer 121 failure status for selected DMA channel. The 122 MSS_PDMA_clear_transfer_complete_status() function can be used to clear the 123 DMA transfer success status. 124 The MSS_PDMA_clear_transfer_error_status() function can be used to clear the 125 DMA transfer error status. 126 127 *//*==========================================================================*/ 128 #ifndef MSS_PDMA_H 129 #define MSS_PDMA_H 130 131 #ifdef __cplusplus 132 extern "C" { 133 #endif 134 135 #include <stdint.h> 136 137 /*---------------------------Public Data Structure----------------------------*/ 138 /*----------------------------------PDMA--------------------------------------*/ 139 140 /*----------------------------------------------------------------------------/* 141 The mss_pdma_channel_id_t enumeration is used to identify peripheral DMA 142 channels. It is used as function parameter to specify the PDMA channel used. 143 */ 144 typedef enum __pdma_channel_id 145 { 146 MSS_PDMA_CHANNEL_0 = 0, 147 MSS_PDMA_CHANNEL_1, 148 MSS_PDMA_CHANNEL_2, 149 MSS_PDMA_CHANNEL_3, 150 MSS_PDMA_lAST_CHANNEL, 151 } mss_pdma_channel_id_t; 152 153 /*-------------------------------------------------------------------------*//** 154 The mss_pdma_channel_config_t structure is used to configure the desired 155 Platform DMA channel. PDMA channel configuration includes configuration of 156 source, destination address and the number of bytes for the DMA transfer. 157 Single DMA transfer may require multiple DMA transactions, the size and 158 alignment of the individual DMA transaction can be forced. The PDMA can be 159 programmed to automatically repeat a transfer. 160 The MSS PDMA have two interrupts per channel, transfer complete interrupt and 161 transfer error interrupt. The two interrupts can be enabled by configuring 162 respective bits in the mss_pdma_channel_config_t structure. 163 */ 164 typedef struct _pdmachannelconfig 165 { 166 volatile uint64_t src_addr; /* source address */ 167 volatile uint64_t dest_addr; /* destination address */ 168 volatile uint64_t num_bytes; /* Number of bytes to be transferred. 169 * Base 2 Logarithm */ 170 volatile uint8_t enable_done_int; /* enable transfer complete interrupt*/ 171 volatile uint8_t enable_err_int; /* enable transfer error interrupt*/ 172 volatile uint8_t repeat; /* repeat the transaction */ 173 volatile uint8_t force_order; /* Enforces strict ordering by only 174 allowing one of each transfer type 175 in-flight at a time */ 176 } mss_pdma_channel_config_t; 177 178 /*------------------------Private data structures-----------------------------*/ 179 /*----------------------------------- PDMA -----------------------------------*/ 180 181 /*------------------------------------------------------------------------*//** 182 * The mss_pdma_error_id_t enumeration is used to specify the error status from 183 * MSS PDMA transfer / transaction functions. 184 */ 185 typedef enum __pdma_error_id_t 186 { 187 MSS_PDMA_OK = 0, //!< PDMA_OK 188 MSS_PDMA_ERROR_INVALID_SRC_ADDR, //!< ERROR_INVALID_SRC_ADDR 189 MSS_PDMA_ERROR_INVALID_DEST_ADDR, //!< ERROR_INVALID_DEST_ADDR 190 MSS_PDMA_ERROR_TRANSACTION_IN_PROGRESS,//!< ERROR_TRANSACTION_IN_PROGRESS 191 MSS_PDMA_ERROR_INVALID_CHANNEL_ID, //!< ERROR_INVALID_CHANNEL_ID 192 MSS_PDMA_ERROR_INVALID_NEXTCFG_WSIZE, //!< ERROR_INVALID_NEXTCFG_WSIZE 193 MSS_PDMA_ERROR_INVALID_NEXTCFG_RSIZE, //!< ERROR_INVALID_NEXTCFG_RSIZE 194 MSS_PDMA_ERROR_LAST_ID, //!< ERROR_LAST_ID 195 } mss_pdma_error_id_t; 196 197 /*-------------------------------------------------------------------------*//** 198 * The mss_pdma_t structure will describe the functionality of the memory mapped 199 * registers in the Platform DMA Engine. 200 */ 201 typedef struct _pdmaregs 202 { 203 volatile uint32_t control_reg; /* Channel Control Register */ 204 volatile uint32_t next_config; /* Next transfer type */ 205 volatile uint64_t next_bytes; /* Number of bytes to be transferred. 206 * Base 2 Logarithm */ 207 volatile uint64_t next_destination; /* Destination Start Address */ 208 volatile uint64_t next_source; /* Source start Address*/ 209 const volatile uint32_t exec_config; /* Active transfer type */ 210 const volatile uint64_t exec_bytes; /* Number of bytes remaining. */ 211 const volatile uint64_t exec_destination;/* Destination current address. */ 212 const volatile uint64_t exec_source; /* Source current address. */ 213 } mss_pdma_t; 214 215 /* PDMA Register base address. */ 216 #define PDMA_REG_BASE 0x03000000U 217 218 /* PDMA Channel Register offset.*/ 219 #define PDMA_CHL_REG_OFFSET 0x1000U 220 221 #define MASK_PDMA_CONTROL_RUN 0x02U 222 223 #define MASK_CLAIM_PDMA_CHANNEL 0x01U 224 225 #define MASK_PDMA_ENABLE_DONE_INT 0x00004000U 226 #define MASK_PDMA_ENABLE_ERR_INT 0x00008000U 227 228 #define SHIFT_CH_CONFIG_WSIZE 24U 229 #define SHIFT_CH_CONFIG_RSIZE 28U 230 231 #define MASK_MAXIUM_WSIZE 0x0F000000U 232 #define MASK_MAXIUM_RSIZE 0xF0000000U 233 234 #define MASK_REPEAT_TRANSCTION 0x04U 235 #define MASK_FORCE_ORDERING 0x08U 236 237 #define MASK_PDMA_TRANSFER_ERROR 0x80000000U 238 #define MASK_PDMA_TRANSFER_DONE 0x40000000U 239 240 /*--------------------------------Public APIs---------------------------------*/ 241 242 /*-------------------------------------------------------------------------*//** 243 The MSS_PDMA_init() function is used to initialize the PolarFire SoC MSS 244 Platform DMA engine. It initializes the basic data structures required for 245 driver functionality. 246 @param 247 This function does not need any parameters. 248 249 @return 250 This function does not return value. 251 @endcode 252 */ 253 void 254 MSS_PDMA_init 255 ( 256 void 257 ); 258 259 /*-------------------------------------------------------------------------*//** 260 The MSS_PDMA_setup_transfer() function is used to configure an individual 261 DMA channel. Apart from selecting the DMA channel the MSS_PDMA_setup_transfer() 262 function will also setup the transfer size, source and destination addresses. 263 This function will also configure the repeat and force order requirements as 264 the PolarFire SoC MSS Peripheral DMA supports multiple simultaneous transfers. 265 Once transfer is setup, it can be started. 266 267 @param channel_id 268 The channel_id parameter specifies the Platform DMA channel selected 269 for DMA transaction. 270 271 @param channel_config 272 The channel_config parameter structure contains the data needed for 273 a DMA transfer. 274 - Source Address 275 - Destination address 276 - Number of Bytes 277 - Enable the Done Interrupt 278 - Enable the ErrorInterrupt 279 - Set the active transfer type, single or repeat. 280 - Force Order. 281 282 @return pdma_error_id_t 283 The function returns error signals of type mss_pdma_error_id_t. 284 285 Example: 286 The following call will configure channel 0 287 @code 288 g_pdma_error_code = MSS_PDMA_setup_transfer(PDMA_CHANNEL_0, 289 &pdma_config_ch0); 290 @endcode 291 */ 292 mss_pdma_error_id_t 293 MSS_PDMA_setup_transfer 294 ( 295 mss_pdma_channel_id_t channel_id, 296 mss_pdma_channel_config_t *channel_config 297 ); 298 299 /*-------------------------------------------------------------------------*//** 300 The MSS_PDMA_start_transfer() function is used to initiate an individual 301 transfer on selected DMA channel . The source and destination address of 302 the transfer and the number of bytes to be transferred must be configured 303 before calling this function. 304 305 @param channel_id 306 The channel_id parameter specifies the Platform DMA channel selected 307 for DMA transaction. 308 309 @return 310 The function returns error signals of type mss_pdma_error_id_t. 311 312 Example: 313 The following call will configure channel 0 314 @code 315 /*Setup the PDMA channel for transfer 316 g_pdma_error_code = MSS_PDMA_setup_transfer(PDMA_CHANNEL_0, 317 &pdma_config_ch0); 318 319 /*Initiate the transfer for channel 0. 320 MSS_PDMA_start_transfer(PDMA_CHANNEL_0); 321 @endcode 322 */ 323 mss_pdma_error_id_t 324 MSS_PDMA_start_transfer 325 ( 326 mss_pdma_channel_id_t channel_id 327 ); 328 329 /*-------------------------------------------------------------------------*//** 330 The MSS_PDMA_set_transction_size() function is used to set a channel 331 DMA transaction size. The write_size and read_size buffers are used to 332 determine the size and alignment of individual PDMA transaction as a single 333 PDMA transfer may require multiple transaction. 334 335 @param channel_id 336 The channel_id parameter specifies the Platform DMA channel selected 337 for DMA transaction. 338 339 @param write_size 340 The write_size parameter specifies the base 2 logarithm of PDMA 341 transaction. 342 e.g. 0 is 1 byte, 3 is 8 bytes, 5 is 32 bytes 343 344 @param read_size 345 The read_size parameter specifies the base 2 logarithm of PDMA 346 transaction. 347 e.g. 0 is 1 byte, 3 is 8 bytes, 5 is 32 bytes 348 349 @return 350 The function returns error signals of type mss_pdma_error_id_t. 351 352 Example: 353 The following call will configure channel 0 transaction to 32bytes. 354 @code 355 MSS_PDMA_set_transction_size(PDMA_CHANNEL_0, 356 write_size, 357 read_size) 358 @endcode 359 */ 360 mss_pdma_error_id_t 361 MSS_PDMA_set_transction_size 362 ( 363 mss_pdma_channel_id_t channel_id, 364 uint8_t write_size, 365 uint8_t read_size 366 ); 367 368 /*-------------------------------------------------------------------------*//** 369 The MSS_PDMA_get_active_transfer_type() function is used to request active 370 transfer type for selected DMA channel. 371 The transfer type for the DMA channel was configured during the channel 372 configuration process, calling this function will read the transfer type 373 from the configured DMA channel. 374 375 @param channel_id 376 The channel_id parameter specifies the Platform DMA channel selected 377 for DMA transaction. 378 379 @return 380 This function returns a 32-bit value indicating the active transfer 381 type of the DMA channel. 382 383 Example: 384 The following call will return the Channel (0) active transfer type. 385 386 @code 387 MSS_PDMA_get_active_transfer_type(PDMA_CHANNEL_0); 388 @endcode 389 */ 390 uint32_t 391 MSS_PDMA_get_active_transfer_type 392 ( 393 mss_pdma_channel_id_t channel_id 394 ); 395 396 /*-------------------------------------------------------------------------*//** 397 The MSS_PDMA_get_number_bytes_remaining() function is used to request number 398 of bytes remaining to be transferred. 399 400 @param channel_id 401 The channel_id parameter specifies the Platform DMA channel selected 402 for DMA transaction. 403 404 @return 405 This function return 64-bit value indicating number of bytes 406 remaining to be transferred. 407 408 Example: 409 The following call will return the number of bytes remaining Channel (0). 410 411 @code 412 MSS_PDMA_get_number_bytes_remaining(PDMA_CHANNEL_0); 413 @endcode 414 */ 415 uint64_t 416 MSS_PDMA_get_number_bytes_remaining 417 ( 418 mss_pdma_channel_id_t channel_id 419 ); 420 421 /*-------------------------------------------------------------------------*//** 422 The MSS_PDMA_get_destination_current_addr() function is used to request the 423 channel Destination address. 424 425 @param channel_id 426 The channel_id parameter specifies the Platform DMA channel selected 427 for DMA transaction. 428 429 @return 430 This function return 64-bit value indicating destination address of 431 the selected DMA channel. 432 433 Example: 434 The following call will return the Channel (0) Destination address register 435 value. 436 437 @code 438 MSS_PDMA_get_destination_current_addr(PDMA_CHANNEL_0); 439 @endcode 440 */ 441 uint64_t 442 MSS_PDMA_get_destination_current_addr 443 ( 444 mss_pdma_channel_id_t channel_id 445 ); 446 447 /*-------------------------------------------------------------------------*//** 448 The MSS_PDMA_get_source_current_addr() function is used to request the 449 channel Source address. 450 451 @param channel_id 452 The channel_id parameter specifies the Platform DMA channel selected 453 for DMA transaction. 454 455 @return 456 This function return 64-bit value indicating source address of 457 the selected DMA channel. 458 459 Example: 460 The following call will return the Channel (0) Source address register 461 value. 462 463 @code 464 MSS_PDMA_get_source_current_addr(PDMA_CHANNEL_0); 465 @endcode 466 */ 467 uint64_t 468 MSS_PDMA_get_source_current_addr 469 ( 470 mss_pdma_channel_id_t channel_id 471 ); 472 473 /*-------------------------------------------------------------------------*//** 474 The MSS_PDMA_get_transfer_complete_status() function is used to request the 475 completion status of last DMA transfer. 476 477 @param channel_id 478 The channel_id parameter specifies the Platform DMA channel selected 479 for DMA transaction. 480 481 @return 482 This function return 8-bit value indicating completion status of the 483 last DMA transfer. 484 485 Example: 486 The following call will return the Channel (0) transfer status. 487 488 @code 489 MSS_PDMA_get_transfer_complete_status(PDMA_CHANNEL_0); 490 @endcode 491 492 */ 493 uint8_t 494 MSS_PDMA_get_transfer_complete_status 495 ( 496 mss_pdma_channel_id_t channel_id 497 ); 498 499 /*-------------------------------------------------------------------------*//** 500 The MSS_PDMA_get_transfer_error_status() function is used to request the 501 error status of last DMA transfer. 502 503 @param channel_id 504 The channel_id parameter specifies the Platform DMA channel selected 505 for DMA transaction. 506 507 @return 508 This function return 8-bit value indicating the error status of the 509 last DMA transfer. 510 511 Example: 512 The following call will return the Channel (0) transfer error status. 513 514 @code 515 MSS_PDMA_get_transfer_error_status(PDMA_CHANNEL_0); 516 @endcode 517 518 */ 519 uint8_t 520 MSS_PDMA_get_transfer_error_status 521 ( 522 mss_pdma_channel_id_t channel_id 523 ); 524 525 /*-------------------------------------------------------------------------*//** 526 The MSS_PDMA_clear_transfer_complete_status() function is used to request the 527 transfer complete interrupt status. If the function returns one, that indicates 528 that the transfer is complete and the transfer complete interrupt is cleared. 529 530 @param channel_id 531 The channel_id parameter specifies the Platform DMA channel selected 532 for DMA transaction. 533 534 @return 535 This function return 8-bit value indicating the transfer complete 536 interrupt status of the last DMA transfer. 537 538 Example: 539 The following call will return the Channel (0) transfer complete 540 interrupt status of the last DMA transfer 541 542 @code 543 MSS_PDMA_clear_transfer_complete_status(PDMA_CHANNEL_0); 544 @endcode 545 */ 546 uint8_t 547 MSS_PDMA_clear_transfer_complete_status 548 ( 549 mss_pdma_channel_id_t channel_id 550 ); 551 552 /*-------------------------------------------------------------------------*//** 553 The MSS_PDMA_clear_transfer_error_status() function is used to request the 554 transfer error interrupt status. If the function returns one, that indicates 555 that the transfer error has occurred and error interrupt is cleared. 556 557 @param channel_id 558 The channel_id parameter specifies the Platform DMA channel selected 559 for DMA transaction. 560 561 @return 562 This function return 8-bit value indicating the transfer error 563 interrupt status of the last DMA transfer. 564 565 Example: 566 The following call will return the Channel (0) transfer error 567 interrupt status of the last DMA transfer 568 569 @code 570 MSS_PDMA_clear_transfer_complete_status(PDMA_CHANNEL_0); 571 @endcode 572 573 */ 574 uint8_t 575 MSS_PDMA_clear_transfer_error_status 576 ( 577 mss_pdma_channel_id_t channel_id 578 ); 579 580 #endif /* MSS_PDMA_H */ 581