1 /*
2  * Copyright (c) 2023 Arm Limited
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "mhu_v3_x.h"
18 
19 #include <stddef.h>
20 #include <stdint.h>
21 #include <stdbool.h>
22 
23 /**
24  * \brief Postbox control page structure
25  */
26 struct _mhu_v3_x_pbx_ctrl_reg_t {
27     /* Offset: 0x000 (R/ ) Postbox Block Identifier */
28     const volatile uint32_t mhu_blk_id;
29     /* Offset: 0x004 (R/ ) Reserved */
30     const volatile uint8_t reserved_0[0x10 - 0x04];
31     /* Offset: 0x010 (R/ ) Postbox Feature Support 0 */
32     const volatile uint32_t pbx_feat_spt0;
33     /* Offset: 0x014 (R/ ) Postbox Feature Support 1 */
34     const volatile uint32_t pbx_feat_spt1;
35     /* Offset: 0x018 (R/ ) Reserved */
36     const volatile uint8_t reserved_1[0x20 - 0x18];
37     /* Offset: 0x020 (R/ ) Postbox Doorbell Channel Configuration 0 */
38     const volatile uint32_t pbx_dbch_cfg0;
39     /* Offset: 0x024 (R/ ) Reserved */
40     const volatile uint8_t reserved_2[0x30 - 0x24];
41     /* Offset: 0x030 (R/ ) Postbox FIFO Channel Configuration 0 */
42     const volatile uint32_t pbx_ffch_cfg0;
43     /* Offset: 0x034 (R/ ) Reserved */
44     const volatile uint8_t reserved_3[0x40 - 0x34];
45     /* Offset: 0x040 (R/ ) Postbox Fast Channel Configuration 0 */
46     const volatile uint32_t pbx_fch_cfg0;
47     /* Offset: 0x044 (R/ ) Reserved */
48     const volatile uint8_t reserved_4[0x100 - 0x44];
49     /* Offset: 0x100 (R/W) Postbox control */
50     volatile uint32_t pbx_ctrl;
51     /* Offset: 0x164 (R/ ) Reserved */
52     const volatile uint8_t reserved_5[0x400 - 0x104];
53     /*
54      * Offset: 0x400 (R/ ) Postbox Doorbell Channel Interrupt Status n, where
55      * n is 0 - 3.
56      */
57     const volatile uint32_t pbx_dbch_int_st[4];
58     /*
59      * Offset: 0x410 (R/ ) Postbox FIFO Channel <n> Interrupt Status n, where n
60      * is 0 - 1.
61      */
62     const volatile uint32_t pbx_ffch_int_st[2];
63     /* Offset: 0x418 (R/ ) Reserved */
64     const uint8_t reserved_6[0xFC8 - 0x418];
65     /* Offset: 0xFC8 (R/ ) Postbox Implementer Identification Register */
66     const volatile uint32_t iidr;
67     /* Offset: 0xFCC (R/ ) Postbox Architecture Identification Register */
68     const volatile uint32_t aidr;
69     /*
70      * Offset: 0xFD0 (R/ ) Postbox Implementation Defined Identification
71      * Register n, where n is 0 - 11.
72      */
73     const volatile uint32_t impl_def_id[12];
74 };
75 
76 /**
77  * \brief Postbox doorbell channel window page structure
78  */
79 struct _mhu_v3_x_pbx_pdbcw_reg_t {
80     /* Offset: 0x000 (R/ ) Postbox Doorbell Channel Window Status */
81     const volatile uint32_t pdbcw_st;
82     /* Offset: 0x004 (R/ ) Reserved */
83     const uint8_t reserved_0[0xC - 0x4];
84     /* Offset: 0x00C ( /W) Postbox Doorbell Channel Window Set */
85     volatile uint32_t pdbcw_set;
86     /* Offset: 0x010 (R/ ) Postbox Doorbell Channel Window Interrupt Status */
87     const volatile uint32_t pdbcw_int_st;
88     /* Offset: 0x014 ( /W) Postbox Doorbell Channel Window Interrupt Clear */
89     volatile uint32_t pdbcw_int_clr;
90     /* Offset: 0x018 (R/W) Postbox Doorbell Channel Window Interrupt Enable */
91     volatile uint32_t pdbcw_int_en;
92     /* Offset: 0x01C (R/W) Postbox Doorbell Channel Window Control */
93     volatile uint32_t pdbcw_ctrl;
94 };
95 
96 /**
97  * \brief Postbox structure
98  */
99 struct _mhu_v3_x_pbx {
100     /* Postbox Control */
101     struct _mhu_v3_x_pbx_ctrl_reg_t pbx_ctrl_page;
102     /* Postbox Doorbell Channel Window */
103     struct _mhu_v3_x_pbx_pdbcw_reg_t pdbcw_page;
104 };
105 
106 /**
107  * \brief Mailbox control page structure
108  */
109 struct _mhu_v3_x_mbx_ctrl_reg_t {
110     /* Offset: 0x000 (R/ ) Mailbox Block Identifier */
111     const volatile uint32_t mhu_blk_id;
112     /* Offset: 0x004 (R/ ) Reserved */
113     const volatile uint8_t reserved_0[0x10 - 0x04];
114     /* Offset: 0x010 (R/ ) Mailbox Feature Support 0 */
115     const volatile uint32_t mbx_feat_spt0;
116     /* Offset: 0x014 (R/ ) Mailbox Feature Support 1 */
117     const volatile uint32_t mbx_feat_spt1;
118     /* Offset: 0x018 (R/ ) Reserved */
119     const volatile uint8_t reserved_1[0x20 - 0x18];
120     /* Offset: 0x020 (R/ ) Mailbox Doorbell Channel Configuration 0 */
121     const volatile uint32_t mbx_dbch_cfg0;
122     /* Offset: 0x024 (R/ ) Reserved */
123     const volatile uint8_t reserved_2[0x30 - 0x24];
124     /* Offset: 0x030 (R/ ) Mailbox FIFO Channel Configuration 0 */
125     const volatile uint32_t mbx_ffch_cfg0;
126     /* Offset: 0x034 (R/ ) Reserved */
127     const volatile uint8_t reserved_4[0x40 - 0x34];
128     /* Offset: 0x040 (R/ ) Mailbox Fast Channel Configuration 0 */
129     const volatile uint32_t mbx_fch_cfg0;
130     /* Offset: 0x044 (R/ ) Reserved */
131     const volatile uint8_t reserved_5[0x100 - 0x44];
132     /* Offset: 0x100 (R/W) Mailbox control */
133     volatile uint32_t mbx_ctrl;
134     /* Offset: 0x104 (R/ ) Reserved */
135     const volatile uint8_t reserved_6[0x140 - 0x104];
136     /* Offset: 0x140 (R/W) Mailbox Fast Channel control */
137     volatile uint32_t mbx_fch_ctrl;
138     /* Offset: 0x144 (R/W) Mailbox Fast Channel Group Interrupt Enable */
139     volatile uint32_t mbx_fcg_int_en;
140     /* Offset: 0x148 (R/ ) Reserved */
141     const volatile uint8_t reserved_7[0x400 - 0x148];
142     /*
143      * Offset: 0x400 (R/ ) Mailbox Doorbell Channel Interrupt Status n, where
144      * n = 0 - 3.
145      */
146     const volatile uint32_t mbx_dbch_int_st[4];
147     /*
148      * Offset: 0x410 (R/ ) Mailbox FIFO Channel Interrupt Status n, where
149      * n = 0 - 1.
150      */
151     const volatile uint32_t mbx_ffch_int_st[2];
152     /* Offset: 0x418 (R/ ) Reserved */
153     const volatile uint8_t reserved_8[0x470 - 0x418];
154     /* Offset: 0x470 (R/ ) Mailbox Fast Channel Group Interrupt Status */
155     const volatile uint32_t mbx_fcg_int_st;
156     /* Offset: 0x474 (R/ ) Reserved */
157     const volatile uint8_t reserved_9[0x480 - 0x474];
158     /*
159      * Offset: 0x480 (R/ ) Mailbox Fast Channel Group <n> Interrupt Status,
160      * where n = 0 - 31.
161      */
162     const volatile uint32_t mbx_fch_grp_int_st[32];
163     /* Offset: 0x500 (R/ ) Reserved */
164     const volatile uint8_t reserved_10[0xFC8 - 0x500];
165     /* Offset: 0xFC8 (R/ ) Mailbox Implementer Identification Register */
166     const volatile uint32_t iidr;
167     /* Offset: 0xFCC (R/ ) Mailbox Architecture Identification Register */
168     const volatile uint32_t aidr;
169     /*
170      * Offset: 0xFD0 (R/ ) Mailbox Implementation Defined Identification
171      * Register n, where n is 0 - 11.
172      */
173     const volatile uint32_t impl_def_id[12];
174 };
175 
176 /**
177  * \brief Mailbox doorbell channel window page structure
178  */
179 struct _mhu_v3_x_mbx_mdbcw_reg_t {
180     /* Offset: 0x000 (R/ ) Mailbox Doorbell Channel Window Status */
181     const volatile uint32_t mdbcw_st;
182     /* Offset: 0x004 (R/ ) Mailbox Doorbell Channel Window Status Masked */
183     const volatile uint32_t mdbcw_st_msk;
184     /* Offset: 0x008 ( /W) Mailbox Doorbell Channel Window Clear */
185     volatile uint32_t mdbcw_clr;
186     /* Offset: 0x00C (R/ ) Reserved */
187     const volatile uint8_t reserved_0[0x10 - 0x0C];
188     /* Offset: 0x010 (R/ ) Mailbox Doorbell Channel Window Mask Status */
189     const volatile uint32_t mdbcw_msk_st;
190     /* Offset: 0x014 ( /W) Mailbox Doorbell Channel Window Mask Set */
191     volatile uint32_t mdbcw_msk_set;
192     /* Offset: 0x018 ( /W) Mailbox Doorbell Channel Window Mask Clear */
193     volatile uint32_t mdbcw_msk_clr;
194     /* Offset: 0x01C (R/W) Mailbox Doorbell Channel Window Control */
195     volatile uint32_t mdbcw_ctrl;
196 };
197 
198 /**
199  * \brief Mailbox structure
200  */
201 struct _mhu_v3_x_mbx {
202    /* Mailbox control */
203    struct _mhu_v3_x_mbx_ctrl_reg_t mbx_ctrl_page;
204    /* Mailbox Doorbell Channel Window */
205    struct _mhu_v3_x_mbx_mdbcw_reg_t mdbcw_page;
206 };
207 
208 /**
209  * \brief MHUv3 frame type
210  */
211 union _mhu_v3_x_frame_t {
212     /* Postbox Frame */
213     struct _mhu_v3_x_pbx pbx_frame;
214     /* Mailbox Frame */
215     struct _mhu_v3_x_mbx mbx_frame;
216 };
217 
218 /**
219  * \brief Enables the doorbell channel to contribute to combined interrupt
220  *
221  * \param[in] dev        MHU device struct \ref mhu_v3_x_dev_t
222  * \param[in] channel    Channel number
223  *
224  * \return Nothing
225  *
226  * \note For sender channels, transfer acknowledge event interrupt is also
227  *       enabled.
228  */
_mhu_v3_x_doorbell_interrupt_enable(const struct mhu_v3_x_dev_t * dev,uint32_t channel)229 static void _mhu_v3_x_doorbell_interrupt_enable(
230      const struct mhu_v3_x_dev_t *dev, uint32_t channel)
231 {
232     union _mhu_v3_x_frame_t *p_mhu;
233 
234     p_mhu = (union _mhu_v3_x_frame_t *)dev->base;
235 
236     if(dev->frame == MHU_V3_X_PBX_FRAME) {
237         struct _mhu_v3_x_pbx_pdbcw_reg_t *pdbcw_reg;
238         pdbcw_reg = (struct _mhu_v3_x_pbx_pdbcw_reg_t *)
239             &(p_mhu->pbx_frame.pdbcw_page);
240 
241         /*
242          * Enable this doorbell channel to generate interrupts for transfer
243          * acknowledge events.
244          */
245         pdbcw_reg[channel].pdbcw_int_en = 0x1;
246 
247         /*
248          * Enable this doorbell channel to contribute to the PBX combined
249          * interrupt.
250          */
251         pdbcw_reg[channel].pdbcw_ctrl = 0x1;
252     } else {
253         struct _mhu_v3_x_mbx_mdbcw_reg_t *mdbcw_reg;
254         mdbcw_reg = (struct _mhu_v3_x_mbx_mdbcw_reg_t *)
255             &(p_mhu->mbx_frame.mdbcw_page);
256 
257         /*
258          * Enable this doorbell channel to contribute to the MBX combined
259          * interrupt.
260          */
261         mdbcw_reg[channel].mdbcw_ctrl = 0x1;
262     }
263 }
264 
265 /**
266  * \brief Disables the doorbell channel from contributing to combined interrupt
267  *
268  * \param[in] dev        MHU device struct \ref mhu_v3_x_dev_t
269  * \param[in] channel    Channel number
270  *
271  * \return Nothing
272  *
273  * \note For sender channels, transfer acknowledge event interrupt is also
274  *       disabled.
275  */
_mhu_v3_x_doorbell_interrupt_disable(const struct mhu_v3_x_dev_t * dev,uint32_t channel)276 static void _mhu_v3_x_doorbell_interrupt_disable(
277      const struct mhu_v3_x_dev_t *dev, uint32_t channel)
278 {
279     union _mhu_v3_x_frame_t *p_mhu;
280 
281     p_mhu = (union _mhu_v3_x_frame_t *)dev->base;
282 
283     if(dev->frame == MHU_V3_X_PBX_FRAME) {
284         struct _mhu_v3_x_pbx_pdbcw_reg_t *pdbcw_reg;
285         pdbcw_reg = (struct _mhu_v3_x_pbx_pdbcw_reg_t *)
286             &(p_mhu->pbx_frame.pdbcw_page);
287 
288         /* Clear channel transfer acknowledge event interrupt */
289         pdbcw_reg[channel].pdbcw_int_clr = 0x1;
290 
291         /* Disable channel transfer acknowledge event interrupt */
292         pdbcw_reg[channel].pdbcw_int_en &= ~(0x1);
293 
294         /*
295          * Disable this doorbell channel from contributing to the PBX combined
296          * interrupt.
297          */
298         pdbcw_reg[channel].pdbcw_ctrl &= ~(0x1);
299     } else {
300         struct _mhu_v3_x_mbx_mdbcw_reg_t *mdbcw_reg;
301         mdbcw_reg = (struct _mhu_v3_x_mbx_mdbcw_reg_t *)
302             &(p_mhu->mbx_frame.mdbcw_page);
303 
304         /*
305          * Disable this doorbell channel from contributing to the MBX combined
306          * interrupt.
307          */
308         mdbcw_reg[channel].mdbcw_ctrl &= ~(0x1);
309     }
310 }
311 
312 /**
313  * \brief Clears the doorbell channel transfer acknowledge event interrupt
314  *
315  * \param[in] dev        MHU device struct \ref mhu_v3_x_dev_t
316  * \param[in] channel    Channel number
317  *
318  * \return Nothing
319  */
_mhu_v3_x_doorbell_interrupt_clear(const struct mhu_v3_x_dev_t * dev,uint32_t channel)320 static void _mhu_v3_x_doorbell_interrupt_clear(
321      const struct mhu_v3_x_dev_t *dev, uint32_t channel)
322 {
323     union _mhu_v3_x_frame_t *p_mhu;
324     struct _mhu_v3_x_pbx_pdbcw_reg_t *pdbcw_reg;
325 
326     p_mhu = (union _mhu_v3_x_frame_t *)dev->base;
327     pdbcw_reg = (struct _mhu_v3_x_pbx_pdbcw_reg_t *)&(p_mhu->
328             pbx_frame.pdbcw_page);
329 
330     /* Clear channel transfer acknowledge event interrupt */
331     pdbcw_reg[channel].pdbcw_int_clr = 0x1;
332 }
333 
mhu_v3_x_driver_init(struct mhu_v3_x_dev_t * dev)334 enum mhu_v3_x_error_t mhu_v3_x_driver_init(struct mhu_v3_x_dev_t *dev)
335 {
336     uint32_t aidr = 0;
337     uint8_t mhu_major_rev;
338     union _mhu_v3_x_frame_t *p_mhu;
339 
340     if (dev == NULL) {
341         return MHU_V_3_X_ERR_INVALID_PARAM;
342     }
343 
344     /* Return if already initialized */
345     if (dev->is_initialized) {
346         return MHU_V_3_X_ERR_NONE;
347     }
348 
349     p_mhu = (union _mhu_v3_x_frame_t *)dev->base;
350 
351     /* Read revision from MHU hardware */
352     if (dev->frame == MHU_V3_X_MBX_FRAME) {
353         aidr = p_mhu->mbx_frame.mbx_ctrl_page.aidr;
354     } else {
355         aidr = p_mhu->pbx_frame.pbx_ctrl_page.aidr;
356     }
357 
358     /* Read the MHU Architecture Major Revision */
359     mhu_major_rev =
360         ((aidr & MHU_ARCH_MAJOR_REV_MASK) >> MHU_ARCH_MAJOR_REV_OFF);
361 
362     /* Return error if the MHU major revision is not 3 */
363     if (mhu_major_rev != MHU_MAJOR_REV_V3) {
364         /* Unsupported MHU version */
365         return MHU_V_3_X_ERR_UNSUPPORTED_VERSION;
366     }
367 
368     /* Read the MHU Architecture Minor Revision */
369     dev->subversion =
370         ((aidr & MHU_ARCH_MINOR_REV_MASK) >> MHU_ARCH_MINOR_REV_MASK);
371 
372     /* Return error if the MHU minor revision is not 0 */
373     if (dev->subversion != MHU_MINOR_REV_3_0) {
374         /* Unsupported subversion */
375         return MHU_V_3_X_ERR_UNSUPPORTED_VERSION;
376     }
377 
378     /* Initialize the Postbox/Mailbox to remain in operational state */
379     if (dev->frame == MHU_V3_X_MBX_FRAME) {
380         p_mhu->mbx_frame.mbx_ctrl_page.mbx_ctrl |= MHU_V3_OP_REQ;
381     } else{
382         p_mhu->pbx_frame.pbx_ctrl_page.pbx_ctrl |= MHU_V3_OP_REQ;
383     }
384 
385     dev->is_initialized = true;
386 
387     return MHU_V_3_X_ERR_NONE;
388 }
389 
mhu_v3_x_get_num_channel_implemented(const struct mhu_v3_x_dev_t * dev,enum mhu_v3_x_channel_type_t ch_type,uint8_t * num_ch)390 enum mhu_v3_x_error_t mhu_v3_x_get_num_channel_implemented(
391      const struct mhu_v3_x_dev_t *dev,
392      enum mhu_v3_x_channel_type_t ch_type, uint8_t *num_ch)
393 {
394     union _mhu_v3_x_frame_t *p_mhu;
395 
396     if ((dev == NULL) || (num_ch == NULL)) {
397         return MHU_V_3_X_ERR_INVALID_PARAM;
398     }
399 
400     p_mhu = (union _mhu_v3_x_frame_t *)dev->base;
401 
402     /* Only doorbell channel is supported */
403     if (ch_type != MHU_V3_X_CHANNEL_TYPE_DBCH) {
404         return MHU_V_3_X_ERR_UNSUPPORTED;
405     }
406 
407     /* Read the number of channels implemented in the MHU */
408     if(dev->frame == MHU_V3_X_PBX_FRAME) {
409         *num_ch = (p_mhu->pbx_frame.pbx_ctrl_page.pbx_dbch_cfg0 + 1);
410     } else {
411         *num_ch = (p_mhu->mbx_frame.mbx_ctrl_page.mbx_dbch_cfg0 + 1);
412     }
413 
414     return MHU_V_3_X_ERR_NONE;
415 }
416 
mhu_v3_x_doorbell_clear(struct mhu_v3_x_dev_t * dev,uint32_t channel,uint32_t mask)417 enum mhu_v3_x_error_t mhu_v3_x_doorbell_clear(struct mhu_v3_x_dev_t *dev,
418      uint32_t channel, uint32_t mask)
419 {
420     union _mhu_v3_x_frame_t *p_mhu;
421     struct _mhu_v3_x_mbx_mdbcw_reg_t *mdbcw_reg;
422     enum mhu_v3_x_error_t status;
423 
424     if (dev == NULL) {
425         return MHU_V_3_X_ERR_INVALID_PARAM;
426     }
427 
428     /* Check if driver has been initialized */
429     if (!(dev->is_initialized)) {
430         status = mhu_v3_x_driver_init(dev);
431         if (status != MHU_V_3_X_ERR_NONE) {
432             return status;
433         }
434     }
435 
436     /* Only MBX can clear the Doorbell channel */
437     if(dev->frame != MHU_V3_X_MBX_FRAME) {
438         return MHU_V_3_X_ERR_INVALID_PARAM;
439     }
440 
441     p_mhu = (union _mhu_v3_x_frame_t *)dev->base;
442     mdbcw_reg = (struct _mhu_v3_x_mbx_mdbcw_reg_t *)
443         &(p_mhu->mbx_frame.mdbcw_page);
444 
445     /* Clear the bits in the doorbell channel */
446     mdbcw_reg[channel].mdbcw_clr = mask;
447 
448     return MHU_V_3_X_ERR_NONE;
449 }
450 
mhu_v3_x_doorbell_write(struct mhu_v3_x_dev_t * dev,uint32_t channel,uint32_t value)451 enum mhu_v3_x_error_t mhu_v3_x_doorbell_write(struct mhu_v3_x_dev_t *dev,
452      uint32_t channel, uint32_t value)
453 {
454     union _mhu_v3_x_frame_t *p_mhu;
455     struct _mhu_v3_x_pbx_pdbcw_reg_t *pdbcw_reg;
456     enum mhu_v3_x_error_t status;
457 
458     if (dev == NULL) {
459         return MHU_V_3_X_ERR_INVALID_PARAM;
460     }
461 
462     /* Check if driver has been initialized */
463     if (!(dev->is_initialized)) {
464         status = mhu_v3_x_driver_init(dev);
465         if (status != MHU_V_3_X_ERR_NONE) {
466             return status;
467         }
468     }
469 
470     /* Only PBX can set the Doorbell channel value */
471     if (dev->frame != MHU_V3_X_PBX_FRAME) {
472         return MHU_V_3_X_ERR_INVALID_PARAM;
473     }
474 
475     p_mhu = (union _mhu_v3_x_frame_t *)dev->base;
476 
477     pdbcw_reg = (struct _mhu_v3_x_pbx_pdbcw_reg_t *)
478         &(p_mhu->pbx_frame.pdbcw_page);
479 
480     /* Write the value to the doorbell channel */
481     pdbcw_reg[channel].pdbcw_set = value;
482 
483     return MHU_V_3_X_ERR_NONE;
484 }
485 
mhu_v3_x_doorbell_read(struct mhu_v3_x_dev_t * dev,uint32_t channel,uint32_t * value)486 enum mhu_v3_x_error_t mhu_v3_x_doorbell_read(struct mhu_v3_x_dev_t *dev,
487      uint32_t channel, uint32_t *value)
488 {
489     union _mhu_v3_x_frame_t *p_mhu;
490     enum mhu_v3_x_error_t status;
491 
492     if ((dev == NULL) || (value == NULL)) {
493         return MHU_V_3_X_ERR_INVALID_PARAM;
494     }
495 
496     /* Check if driver has been initialized */
497     if (!(dev->is_initialized)) {
498         status = mhu_v3_x_driver_init(dev);
499         if (status != MHU_V_3_X_ERR_NONE) {
500             return status;
501         }
502     }
503 
504     p_mhu = (union _mhu_v3_x_frame_t *)dev->base;
505 
506     if(dev->frame == MHU_V3_X_MBX_FRAME) {
507         struct _mhu_v3_x_mbx_mdbcw_reg_t *mdbcw_reg;
508         mdbcw_reg = (struct _mhu_v3_x_mbx_mdbcw_reg_t *)
509             &(p_mhu->mbx_frame.mdbcw_page);
510 
511         /* Read the value from Mailbox Doorbell status register */
512         *value = mdbcw_reg[channel].mdbcw_st;
513     } else {
514         struct _mhu_v3_x_pbx_pdbcw_reg_t *pdbcw_reg;
515         pdbcw_reg = (struct _mhu_v3_x_pbx_pdbcw_reg_t *)
516             &(p_mhu->pbx_frame.pdbcw_page);
517 
518         /* Read the value from Postbox Doorbell status register */
519         *value = pdbcw_reg[channel].pdbcw_st;
520     }
521 
522     return MHU_V_3_X_ERR_NONE;
523 }
524 
mhu_v3_x_doorbell_mask_set(struct mhu_v3_x_dev_t * dev,uint32_t channel,uint32_t mask)525 enum mhu_v3_x_error_t mhu_v3_x_doorbell_mask_set(
526      struct mhu_v3_x_dev_t *dev, uint32_t channel, uint32_t mask)
527 {
528     union _mhu_v3_x_frame_t *p_mhu;
529     struct _mhu_v3_x_mbx_mdbcw_reg_t *mdbcw_reg;
530     enum mhu_v3_x_error_t status;
531 
532     if (dev == NULL) {
533         return MHU_V_3_X_ERR_INVALID_PARAM;
534     }
535 
536     /* Check if driver has been initialized */
537     if (!(dev->is_initialized) ) {
538         status = mhu_v3_x_driver_init(dev);
539         if (status != MHU_V_3_X_ERR_NONE) {
540             return status;
541         }
542     }
543 
544     /* Doorbell channel mask not applicable for PBX */
545     if(dev->frame != MHU_V3_X_MBX_FRAME) {
546         return MHU_V_3_X_ERR_INVALID_PARAM;
547     }
548 
549     p_mhu = (union _mhu_v3_x_frame_t *)dev->base;
550 
551     mdbcw_reg = (struct _mhu_v3_x_mbx_mdbcw_reg_t *)
552         &(p_mhu->mbx_frame.mdbcw_page);
553 
554     /* Set the Doorbell channel mask */
555     mdbcw_reg[channel].mdbcw_msk_set = mask;
556 
557     return MHU_V_3_X_ERR_NONE;
558 }
559 
mhu_v3_x_doorbell_mask_clear(struct mhu_v3_x_dev_t * dev,uint32_t channel,uint32_t mask)560 enum mhu_v3_x_error_t mhu_v3_x_doorbell_mask_clear(
561      struct mhu_v3_x_dev_t *dev, uint32_t channel, uint32_t mask)
562 {
563     union _mhu_v3_x_frame_t *p_mhu;
564     struct _mhu_v3_x_mbx_mdbcw_reg_t *mdbcw_reg;
565     enum mhu_v3_x_error_t status;
566 
567     if (dev == NULL) {
568         return MHU_V_3_X_ERR_INVALID_PARAM;
569     }
570 
571     /* Check if driver has been initialized */
572     if (!(dev->is_initialized)) {
573         status = mhu_v3_x_driver_init(dev);
574         if (status != MHU_V_3_X_ERR_NONE) {
575             return status;
576         }
577     }
578 
579     /* Doorbell channel mask not applicable for PBX */
580     if(dev->frame != MHU_V3_X_MBX_FRAME) {
581         return MHU_V_3_X_ERR_INVALID_PARAM;
582     }
583 
584     p_mhu = (union _mhu_v3_x_frame_t *)dev->base;
585 
586     mdbcw_reg = (struct _mhu_v3_x_mbx_mdbcw_reg_t *)
587         &(p_mhu->mbx_frame.mdbcw_page);
588 
589     /* Clear the Doorbell channel mask */
590     mdbcw_reg[channel].mdbcw_msk_clr = mask;
591 
592     return MHU_V_3_X_ERR_NONE;
593 }
594 
mhu_v3_x_doorbell_mask_get(struct mhu_v3_x_dev_t * dev,uint32_t channel,uint32_t * mask_status)595 enum mhu_v3_x_error_t mhu_v3_x_doorbell_mask_get(
596      struct mhu_v3_x_dev_t *dev, uint32_t channel, uint32_t *mask_status)
597 {
598     union _mhu_v3_x_frame_t *p_mhu;
599     struct _mhu_v3_x_mbx_mdbcw_reg_t *mdbcw_reg;
600     enum mhu_v3_x_error_t status;
601 
602     if ((dev == NULL) || (mask_status == NULL)) {
603         return MHU_V_3_X_ERR_INVALID_PARAM;
604     }
605 
606     /* Check if driver has been initialized */
607     if (!(dev->is_initialized)) {
608         status = mhu_v3_x_driver_init(dev);
609         if (status != MHU_V_3_X_ERR_NONE) {
610             return status;
611         }
612     }
613 
614     /* Doorbell channel mask not applicable for PBX */
615     if(dev->frame != MHU_V3_X_MBX_FRAME) {
616         return MHU_V_3_X_ERR_INVALID_PARAM;
617     }
618 
619     p_mhu = (union _mhu_v3_x_frame_t *)dev->base;
620 
621     mdbcw_reg = (struct _mhu_v3_x_mbx_mdbcw_reg_t *)
622         &(p_mhu->mbx_frame.mdbcw_page);
623 
624     /* Save the Doorbell channel mask status */
625     *mask_status = mdbcw_reg[channel].mdbcw_msk_st;
626 
627     return MHU_V_3_X_ERR_NONE;
628 }
629 
mhu_v3_x_channel_interrupt_enable(struct mhu_v3_x_dev_t * dev,uint32_t channel,enum mhu_v3_x_channel_type_t ch_type)630 enum mhu_v3_x_error_t mhu_v3_x_channel_interrupt_enable(
631      struct mhu_v3_x_dev_t *dev, uint32_t channel,
632      enum mhu_v3_x_channel_type_t ch_type)
633 {
634     enum mhu_v3_x_error_t status;
635 
636     if (dev == NULL) {
637         return MHU_V_3_X_ERR_INVALID_PARAM;
638     }
639 
640     /* Check if driver has been initialized */
641     if (!(dev->is_initialized)) {
642         status = mhu_v3_x_driver_init(dev);
643         if (status != MHU_V_3_X_ERR_NONE) {
644             return status;
645         }
646     }
647 
648     /* Only doorbell channel is supported */
649     if (ch_type != MHU_V3_X_CHANNEL_TYPE_DBCH) {
650         return MHU_V_3_X_ERR_UNSUPPORTED;
651     }
652 
653     /* Enable the doorbell channel interrupt */
654     _mhu_v3_x_doorbell_interrupt_enable(dev, channel);
655 
656     return MHU_V_3_X_ERR_NONE;
657 }
658 
mhu_v3_x_channel_interrupt_disable(struct mhu_v3_x_dev_t * dev,uint32_t channel,enum mhu_v3_x_channel_type_t ch_type)659 enum mhu_v3_x_error_t mhu_v3_x_channel_interrupt_disable(
660      struct mhu_v3_x_dev_t *dev, uint32_t channel,
661      enum mhu_v3_x_channel_type_t ch_type)
662 {
663     enum mhu_v3_x_error_t status;
664 
665     /* Check if driver has been initialized */
666     if (!(dev->is_initialized)) {
667         status = mhu_v3_x_driver_init(dev);
668         if (status != MHU_V_3_X_ERR_NONE) {
669             return status;
670         }
671     }
672 
673     /* Only doorbell channel is supported */
674     if (ch_type != MHU_V3_X_CHANNEL_TYPE_DBCH) {
675         return MHU_V_3_X_ERR_UNSUPPORTED;
676     }
677 
678     /* Disable the doorbell channel interrupt */
679     _mhu_v3_x_doorbell_interrupt_disable(dev, channel);
680 
681     return MHU_V_3_X_ERR_NONE;
682 }
683 
mhu_v3_x_channel_interrupt_clear(struct mhu_v3_x_dev_t * dev,uint32_t channel,enum mhu_v3_x_channel_type_t ch_type)684 enum mhu_v3_x_error_t mhu_v3_x_channel_interrupt_clear(
685      struct mhu_v3_x_dev_t *dev, uint32_t channel,
686      enum mhu_v3_x_channel_type_t ch_type)
687 {
688     enum mhu_v3_x_error_t status;
689 
690     /* Check if driver has been initialized */
691     if (!(dev->is_initialized)) {
692         status = mhu_v3_x_driver_init(dev);
693         if (status != MHU_V_3_X_ERR_NONE) {
694             return status;
695         }
696     }
697 
698     /* Only doorbell channel is supported */
699     if (ch_type != MHU_V3_X_CHANNEL_TYPE_DBCH) {
700         return MHU_V_3_X_ERR_UNSUPPORTED;
701     }
702 
703     /*
704      * Only postbox doorbell channel transfer acknowledge interrupt can be
705      * cleared manually.
706      */
707     if(dev->frame != MHU_V3_X_PBX_FRAME) {
708         return MHU_V_3_X_ERR_INVALID_PARAM;
709     }
710 
711     /* Clear the postbox doorbell channel transfer acknowledge event */
712     _mhu_v3_x_doorbell_interrupt_clear(dev, channel);
713 
714     return MHU_V_3_X_ERR_NONE;
715 }
716