1// Copyright 2018 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "aml-mailbox.h" 6#include "aml-mailbox-hw.h" 7#include <ddk/binding.h> 8#include <stdint.h> 9#include <stdio.h> 10#include <stdlib.h> 11#include <string.h> 12#include <unistd.h> 13 14#define READ32_MAILBOX_PL_REG(offset) \ 15 readl((uint32_t*)mailbox->mmio_mailbox_payload.vaddr + (offset)) 16#define WRITE32_MAILBOX_PL_REG(offset, value) \ 17 writel(value, (uint32_t*)mailbox->mmio_mailbox_payload.vaddr + (offset)) 18#define READ32_MAILBOX_REG(offset) \ 19 readl((uint32_t*)mailbox->mmio_mailbox.vaddr + (offset)) 20#define WRITE32_MAILBOX_REG(offset, value) \ 21 writel(value, (uint32_t*)mailbox->mmio_mailbox.vaddr + (offset)) 22 23static int aml_get_rx_mailbox(uint32_t tx_mailbox) { 24 switch (tx_mailbox) { 25 case AP_SECURE_MAILBOX: 26 return SCP_SECURE_MAILBOX; 27 case AP_NS_LOW_PRIORITY_MAILBOX: 28 return SCP_NS_LOW_PRIORITY_MAILBOX; 29 case AP_NS_HIGH_PRIORITY_MAILBOX: 30 return SCP_NS_HIGH_PRIORITY_MAILBOX; 31 default: 32 return INVALID_MAILBOX; 33 } 34} 35 36static zx_status_t aml_mailbox_send_cmd(void* ctx, 37 mailbox_channel_t* channel, 38 mailbox_data_buf_t* mdata) { 39 aml_mailbox_t* mailbox = ctx; 40 int rx_mailbox_id; 41 if (!channel || !mdata) { 42 return ZX_ERR_INVALID_ARGS; 43 } 44 45 if (INVALID_MAILBOX == (rx_mailbox_id = 46 aml_get_rx_mailbox(channel->mailbox))) { 47 return ZX_ERR_INVALID_ARGS; 48 } 49 50 mtx_lock(&mailbox->mailbox_chan_lock[channel->mailbox]); 51 aml_mailbox_block_t* rx_mailbox = &vim2_mailbox_block[rx_mailbox_id]; 52 aml_mailbox_block_t* tx_mailbox = &vim2_mailbox_block[channel->mailbox]; 53 54 if (mdata->tx_size != 0) { 55 uint32_t num = GET_NUM_WORDS(mdata->tx_size); 56 uint32_t* tx_payload = (uint32_t*)(mdata->tx_buf); 57 for (uint32_t i = 0; i < num; i++) { 58 // AP writes parameters to Payload 59 WRITE32_MAILBOX_PL_REG(tx_mailbox->payload_offset + i, tx_payload[i]); 60 } 61 } 62 63 // AP writes command to AP Mailbox 64 WRITE32_MAILBOX_REG(tx_mailbox->set_offset, mdata->cmd); 65 66 zx_status_t status = zx_interrupt_wait(mailbox->inth[rx_mailbox_id], NULL); 67 if (status != ZX_OK) { 68 MAILBOX_ERROR("zx_interrupt_wait failed\n"); 69 mtx_unlock(&mailbox->mailbox_chan_lock[channel->mailbox]); 70 return status; 71 } 72 73 // AP reads the Payload to get requested information 74 if (channel->rx_size != 0) { 75 uint32_t num = GET_NUM_WORDS(channel->rx_size); 76 uint32_t* rx_payload = (uint32_t*)(channel->rx_buf); 77 for (uint32_t i = 0; i < num; i++) { 78 rx_payload[i] = READ32_MAILBOX_PL_REG(rx_mailbox->payload_offset + i); 79 } 80 } 81 82 // AP writes to the Mailbox CLR register 83 WRITE32_MAILBOX_REG(rx_mailbox->clr_offset, 1); 84 85 mtx_unlock(&mailbox->mailbox_chan_lock[channel->mailbox]); 86 return ZX_OK; 87} 88 89static void aml_mailbox_release(void* ctx) { 90 aml_mailbox_t* mailbox = ctx; 91 mmio_buffer_release(&mailbox->mmio_mailbox); 92 mmio_buffer_release(&mailbox->mmio_mailbox_payload); 93 for (uint32_t i = 0; i < NUM_MAILBOXES; i++) { 94 zx_interrupt_destroy(mailbox->inth[i]); 95 zx_handle_close(mailbox->inth[i]); 96 } 97 free(mailbox); 98} 99 100static zx_protocol_device_t aml_mailbox_device_protocol = { 101 .version = DEVICE_OPS_VERSION, 102 .release = aml_mailbox_release, 103}; 104 105static mailbox_protocol_ops_t mailbox_ops = { 106 .send_cmd = aml_mailbox_send_cmd, 107}; 108 109static zx_status_t aml_mailbox_bind(void* ctx, zx_device_t* parent) { 110 zx_status_t status = ZX_OK; 111 112 aml_mailbox_t* mailbox = calloc(1, sizeof(aml_mailbox_t)); 113 if (!mailbox) { 114 return ZX_ERR_NO_MEMORY; 115 } 116 117 status = device_get_protocol(parent, ZX_PROTOCOL_PLATFORM_DEV, &mailbox->pdev); 118 if (status != ZX_OK) { 119 MAILBOX_ERROR("Could not get parent protocol\n"); 120 goto fail; 121 } 122 123 pdev_device_info_t info; 124 status = pdev_get_device_info(&mailbox->pdev, &info); 125 if (status != ZX_OK) { 126 MAILBOX_ERROR("pdev_get_device_info failed\n"); 127 goto fail; 128 } 129 130 // Map all MMIOs 131 status = pdev_map_mmio_buffer2(&mailbox->pdev, MMIO_MAILBOX, 132 ZX_CACHE_POLICY_UNCACHED_DEVICE, 133 &mailbox->mmio_mailbox); 134 if (status != ZX_OK) { 135 MAILBOX_ERROR("Could not map mailbox MMIO_MAILBOX %d\n", status); 136 goto fail; 137 } 138 139 status = pdev_map_mmio_buffer2(&mailbox->pdev, MMIO_MAILBOX_PAYLOAD, 140 ZX_CACHE_POLICY_UNCACHED_DEVICE, 141 &mailbox->mmio_mailbox_payload); 142 if (status != ZX_OK) { 143 MAILBOX_ERROR("Could not map mailbox MMIO_MAILBOX_PAYLOAD %d\n", status); 144 goto fail; 145 } 146 147 for (uint32_t i = 0; i < NUM_MAILBOXES; i++) { 148 status = pdev_map_interrupt(&mailbox->pdev, i, 149 &mailbox->inth[i]); 150 if (status != ZX_OK) { 151 MAILBOX_ERROR("pdev_map_interrupt failed %d\n", status); 152 goto fail; 153 } 154 155 mtx_init(&mailbox->mailbox_chan_lock[i], mtx_plain); 156 } 157 158 zx_device_prop_t props[] = { 159 {BIND_PLATFORM_DEV_VID, 0, PDEV_VID_AMLOGIC}, 160 {BIND_PLATFORM_DEV_PID, 0, PDEV_PID_AMLOGIC_S912}, 161 {BIND_PLATFORM_DEV_DID, 0, PDEV_DID_AMLOGIC_SCPI}, 162 }; 163 164 device_add_args_t args = { 165 .version = DEVICE_ADD_ARGS_VERSION, 166 .name = "aml-mailbox", 167 .ctx = mailbox, 168 .ops = &aml_mailbox_device_protocol, 169 .proto_id = ZX_PROTOCOL_MAILBOX, 170 .proto_ops = &mailbox_ops, 171 .props = props, 172 .prop_count = countof(props), 173 }; 174 175 status = pdev_device_add(&mailbox->pdev, 0, &args, NULL); 176 if (status != ZX_OK) { 177 goto fail; 178 } 179 180 return ZX_OK; 181fail: 182 aml_mailbox_release(mailbox); 183 return ZX_OK; 184} 185 186static zx_driver_ops_t aml_mailbox_driver_ops = { 187 .version = DRIVER_OPS_VERSION, 188 .bind = aml_mailbox_bind, 189}; 190 191ZIRCON_DRIVER_BEGIN(aml_mailbox, aml_mailbox_driver_ops, "zircon", "0.1", 4) 192 BI_ABORT_IF(NE, BIND_PROTOCOL, ZX_PROTOCOL_PLATFORM_DEV), 193 BI_ABORT_IF(NE, BIND_PLATFORM_DEV_VID, PDEV_VID_KHADAS), 194 BI_ABORT_IF(NE, BIND_PLATFORM_DEV_PID, PDEV_PID_VIM2), 195 BI_MATCH_IF(EQ, BIND_PLATFORM_DEV_DID, PDEV_DID_AMLOGIC_MAILBOX), 196ZIRCON_DRIVER_END(aml_mailbox) 197