1/*
2 * Copyright 2019, Data61
3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO)
4 * ABN 41 687 119 230.
5 *
6 * This software may be distributed and modified according to the terms of
7 * the BSD 2-Clause license. Note that NO WARRANTY is provided.
8 * See "LICENSE_BSD2.txt" for details.
9 *
10 * @TAG(DATA61_BSD)
11 */
12
13#pragma once
14
15#include <libfdt.h>
16#include <platsupport/irq.h>
17#include <platsupport/io.h>
18#include <platsupport/pmem.h>
19
20/* We make an assumption that the size of the address/size cells are no larger than 2
21 * RISCV does have 128 bits but there are no platforms that use that bit length (yet) */
22#define READ_CELL32(addr) fdt32_ld(addr)
23#define READ_CELL64(addr) fdt64_ld(addr)
24#define READ_CELL(size, addr, offset) (size == 2 ? READ_CELL64(addr + (offset * sizeof(uint32_t))) : \
25                                                   READ_CELL32(addr + (offset * sizeof(uint32_t))))
26
27/*
28 * Type of the callback function that is called for each device register instance
29 * during a call to ps_fdt_walk_registers.
30 *
31 * @param pmem Description of the device register instance.
32 * @param curr_num A number indicating the current register instance that we are currently at.
33 * @param num_regs The total number of register instances that the device that we are walking through has.
34 *
35 * @return 0 on success, otherwise an error code
36 */
37typedef int (*reg_walk_cb_fn_t)(pmem_region_t pmem, unsigned curr_num, size_t num_regs, void *token);
38
39/*
40 * Type of the callback function that is called for each device interrupt
41 * instance during a call to ps_fdt_walk_irqs.
42 *
43 * @param irq Description of the device interrupt instance.
44 * @param curr_num A number indicating the current interrupt instance that we are currently at.
45 * @param num_irqs The total number of interrupt instances that the device that we are walking through has.
46 *
47 * @return 0 on success, otherwise an error code
48 */
49typedef int (*irq_walk_cb_fn_t)(ps_irq_t irq, unsigned curr_num, size_t num_irqs, void *token);
50
51/* An internal private struct used by the utility functions in this library. */
52typedef struct ps_fdt_cookie ps_fdt_cookie_t;
53
54/*
55 * Given a devicetree path, this function will return a cookie that can be used in
56 * the other functions in this library.
57 *
58 * @param io_fdt An initialised IO FDT interface.
59 * @param malloc_ops An initialised malloc interface.
60 * @param path Devicetree path to the device for which you want to use the utility functions on.
61 * @param ret_cookie Storage that will have the pointer to the corresponding cookie written to.
62 *
63 * @returns 0 on success, otherwise -EINVAL, -ENOMEM, or one of the error codes in libfdt
64 */
65int ps_fdt_read_path(ps_io_fdt_t *io_fdt, ps_malloc_ops_t *malloc_ops, const char *path, ps_fdt_cookie_t **ret_cookie);
66
67/*
68 * Cleans up a cookie that was initialised by ps_fdt_read_path.
69 *
70 * @param malloc_ops An initialised malloc interface.
71 * @param cookie A pointer to a initialised cookie.
72 *
73 * @returns 0 on success, otherwise -EINVAL
74 */
75int ps_fdt_cleanup_cookie(ps_malloc_ops_t *malloc_ops, ps_fdt_cookie_t *cookie);
76
77/*
78 * Walks the registers property of the device node (if any) corresponding to the
79 * cookie passed in and calls a callback function at each register instance of
80 * the field.
81 *
82 * @param io_fdt An initialised IO FDT interface.
83 * @param cookie A pointer to a initialised cookie.
84 * @param callback Pointer to a callback function that is called at each register instance of the property.
85 * @param token Pointer to be passed into the callback function when it is called.
86 *
87 * @returns 0 on success, otherwise:
88 *  - one of the error codes in libfdt
89 *  - -EINVAL
90 *  - the error returned by the callback function
91 */
92
93int ps_fdt_walk_registers(ps_io_fdt_t *io_fdt, ps_fdt_cookie_t *cookie, reg_walk_cb_fn_t callback, void *token);
94
95/*
96 * Walks the interrupts/interrupts-extended field of the device node (if any)
97 * corresponding to the cookie passed in and calls a callback function at each
98 * interrupt instance of the field. Note that depending on the interrupt parser
99 * modules available, this function may fail to parse the interrupt property.
100 *
101 * The modules can checked by looking inside the libplatsupport/src/arch/arm/irqchip/ folder.
102 *
103 * @param io_fdt An initialised IO FDT interface.
104 * @param cookie A pointer to a initialised cookie.
105 * @param callback Pointer to a callback function that is called at each interrupt instance of the property.
106 * @param token Pointer to be passed into the callback function when it is called.
107 *
108 * @returns 0 on success, otherwise:
109 *  - one of the error codes in libfdt
110 *  - -EINVAL or -ENOENT for no suitable interrupt parsing module
111 *  - the error returned by the callback function
112 */
113int ps_fdt_walk_irqs(ps_io_fdt_t *io_fdt, ps_fdt_cookie_t *cookie, irq_walk_cb_fn_t callback, void *token);
114
115/*
116 * Convenience function for ps_fdt_walk_registers which does not require a callback but instead
117 * uses an offset to map in the desired registers from a device's registers property. Useful
118 * for when you know the exact structure of the devicetree blob.
119 *  @param io_ops An initialised IO ops interface.
120 *  @param cookie A pointer to an initialised FDT interface cookie.
121 *  @param offset The offset to the desired registers in the device's (that the cookie points to)
122 *  registers property.
123 *  @param ret_pmem A pointer that will have the details of the mapped registered block written to.
124 *  Can be NULL.
125 *
126 *  @returns The virtual address of the registers that were mapped in, NULL on error.
127 */
128void *ps_fdt_index_map_register(ps_io_ops_t *io_ops, ps_fdt_cookie_t *cookie, unsigned offset,
129                                pmem_region_t *ret_pmem);
130
131/*
132 * Convenience function for ps_fdt_walk_irqs which does not require a callback but instead
133 * uses an offset to map in the desired interrupt from a device's interrupts property. Useful
134 * for when you know the exact structure of the devicetree blob.
135 *  @param io_ops An initialised IO ops interface.
136 *  @param cookie A pointer to an initialised FDT interface cookie.
137 *  @param offset The offset to the desired interrupt in the device's (that the cookie points to)
138 *  interrupt property.
139 *  @param irq_callback Callback function that will be associated with the registered interrupt.
140 *  @param irq_callback_data Token that will be passed to the callback function.
141 *
142 *  @returns The IRQ ID of the registered interrupt, a negative error code on error.
143 */
144irq_id_t ps_fdt_index_register_irq(ps_io_ops_t *io_ops, ps_fdt_cookie_t *cookie, unsigned offset,
145                                   irq_callback_fn_t irq_callback, void *irq_callback_data);
146