1/* 2 * Copyright 2020, 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 GNU General Public License version 2. Note that NO WARRANTY is provided. 8 * See "LICENSE_GPLv2.txt" for details. 9 * 10 * @TAG(DATA61_GPL) 11 */ 12 13#include <errno.h> 14 15#include <platsupport/reset.h> 16#include <platsupport/plat/reset.h> 17 18/* NVIDIA interface */ 19#include <tx2bpmp/bpmp.h> /* struct mrq_reset_request */ 20 21extern uint32_t mrq_reset_id_map[]; 22 23typedef struct tx2_reset { 24 ps_io_ops_t *io_ops; 25 struct tx2_bpmp *bpmp; 26} tx2_reset_t; 27 28static inline bool check_valid_reset(reset_id_t id) 29{ 30 return (RESET_TOP_GTE <= id && id < NRESETS); 31} 32 33static int tx2_reset_common(void *data, reset_id_t id, bool assert) 34{ 35 if (!check_valid_reset(id)) { 36 ZF_LOGE("Invalid reset ID"); 37 return -EINVAL; 38 } 39 40 tx2_reset_t *reset = data; 41 uint32_t bpmp_reset_id = mrq_reset_id_map[id]; 42 43 /* Setup a message and make a call to BPMP */ 44 struct mrq_reset_request req = { .reset_id = bpmp_reset_id }; 45 req.cmd = (assert) ? CMD_RESET_ASSERT : CMD_RESET_DEASSERT; 46 47 int bytes_recvd = tx2_bpmp_call(reset->bpmp, MRQ_RESET, &req, sizeof(req), NULL, 0); 48 if (bytes_recvd < 0) { 49 return -EIO; 50 } 51 52 return 0; 53} 54 55static int tx2_reset_assert(void *data, reset_id_t id) 56{ 57 return tx2_reset_common(data, id, true); 58} 59 60static int tx2_reset_deassert(void *data, reset_id_t id) 61{ 62 return tx2_reset_common(data, id, false); 63} 64 65static int interface_search_handler(void *handler_data, void *interface_instance, char **properties) 66{ 67 /* Select the first one that is registered */ 68 tx2_reset_t *reset = handler_data; 69 reset->bpmp = (struct tx2_bpmp *) interface_instance; 70 return PS_INTERFACE_FOUND_MATCH; 71} 72 73int reset_sys_init(ps_io_ops_t *io_ops, void *dependencies, reset_sys_t *reset_sys) 74{ 75 if (!io_ops || !reset_sys) { 76 if (!io_ops) { 77 ZF_LOGE("null io_ops argument"); 78 } 79 80 if (!reset_sys) { 81 ZF_LOGE("null reset_sys argument"); 82 } 83 84 return -EINVAL; 85 } 86 87 int error = 0; 88 tx2_reset_t *reset = NULL; 89 error = ps_calloc(&io_ops->malloc_ops, 1, sizeof(tx2_reset_t), (void **) &reset_sys->data); 90 if (error) { 91 ZF_LOGE("Failed to allocate memory for reset sys internal structure"); 92 error = -ENOMEM; 93 goto fail; 94 } 95 96 reset = reset_sys->data; 97 98 if (dependencies) { 99 reset->bpmp = (struct tx2_bpmp *) dependencies; 100 } else { 101 /* See if there's a registered interface for the BPMP, if not, then we 102 * initialise one ourselves. */ 103 error = ps_interface_find(&io_ops->interface_registration_ops, TX2_BPMP_INTERFACE, 104 interface_search_handler, reset); 105 if (error) { 106 error = ps_calloc(&io_ops->malloc_ops, 1, sizeof(struct tx2_bpmp), (void **) &reset->bpmp); 107 if (error) { 108 ZF_LOGE("Failed to allocate memory for the BPMP structure to be initialised"); 109 goto fail; 110 } 111 112 error = tx2_bpmp_init(io_ops, reset->bpmp); 113 if (error) { 114 ZF_LOGE("Failed to initialise the BPMP"); 115 goto fail; 116 } 117 } 118 } 119 120 reset_sys->reset_assert = &tx2_reset_assert; 121 reset_sys->reset_deassert = &tx2_reset_deassert; 122 123 return 0; 124 125fail: 126 127 if (reset_sys->data) { 128 if (reset->bpmp) { 129 ZF_LOGF_IF(ps_free(&io_ops->malloc_ops, sizeof(struct tx2_bpmp), (void *) reset->bpmp), 130 "Failed to free the BPMP structure after a failed reset subsystem initialisation"); 131 } 132 ZF_LOGF_IF(ps_free(&io_ops->malloc_ops, sizeof(tx2_reset_t), (void *) reset_sys->data), 133 "Failed to free the reset private data after a failed reset subsystem initialisation"); 134 } 135 136 return error; 137} 138