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