1// Copyright 2017 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 <ddk/debug.h> 6#include <gpio/pl061/pl061.h> 7#include <soc/hi3660/hi3660.h> 8 9#include <assert.h> 10#include <stdlib.h> 11#include <stdio.h> 12 13// TODO(voydanoff) Move hard coded values to a header file 14 15// Addresses for GPIO regions 16#define GPIO_0_ADDR 0xe8a0b000 17#define GPIO_18_ADDR 0xff3b4000 18#define GPIO_20_ADDR 0xe8a1f000 19#define GPIO_22_ADDR 0xfff0b000 20#define GPIO_28_ADDR 0xfff1d000 21 22static pl061_gpios_t* find_gpio(hi3660_t* hi3660, uint32_t index) { 23 pl061_gpios_t* gpios; 24 // TODO(voydanoff) consider using a fancier data structure here 25 list_for_every_entry(&hi3660->gpios, gpios, pl061_gpios_t, node) { 26 if (index >= gpios->gpio_start && index < gpios->gpio_start + gpios->gpio_count) { 27 return gpios; 28 } 29 } 30 zxlogf(ERROR, "find_gpio failed for index %u\n", index); 31 return NULL; 32} 33 34static zx_status_t hi3660_gpio_config_in(void* ctx, uint32_t index, uint32_t flags) { 35 hi3660_t* hi3660 = ctx; 36 pl061_gpios_t* gpios = find_gpio(hi3660, index); 37 if (!gpios) { 38 return ZX_ERR_INVALID_ARGS; 39 } 40 return pl061_proto_ops.config_in(gpios, index, flags); 41} 42 43static zx_status_t hi3660_gpio_config_out(void* ctx, uint32_t index, uint8_t initial_value) { 44 hi3660_t* hi3660 = ctx; 45 pl061_gpios_t* gpios = find_gpio(hi3660, index); 46 if (!gpios) { 47 return ZX_ERR_INVALID_ARGS; 48 } 49 return pl061_proto_ops.config_out(gpios, index, initial_value); 50} 51 52static zx_status_t hi3660_gpio_set_alt_function(void* ctx, uint32_t index, uint64_t function) { 53 return ZX_ERR_NOT_SUPPORTED; 54} 55 56static zx_status_t hi3660_gpio_read(void* ctx, uint32_t index, uint8_t* out_value) { 57 hi3660_t* hi3660 = ctx; 58 pl061_gpios_t* gpios = find_gpio(hi3660, index); 59 if (!gpios) { 60 return ZX_ERR_INVALID_ARGS; 61 } 62 return pl061_proto_ops.read(gpios, index, out_value); 63} 64 65static zx_status_t hi3660_gpio_write(void* ctx, uint32_t index, uint8_t value) { 66 hi3660_t* hi3660 = ctx; 67 pl061_gpios_t* gpios = find_gpio(hi3660, index); 68 if (!gpios) { 69 return ZX_ERR_INVALID_ARGS; 70 } 71 return pl061_proto_ops.write(gpios, index, value); 72} 73 74static zx_status_t hi3660_gpio_get_interrupt(void* ctx, uint32_t pin, uint32_t flags, 75 zx_handle_t* out_handle) { 76 return ZX_ERR_NOT_SUPPORTED; 77} 78 79static zx_status_t hi3660_gpio_release_interrupt(void* ctx, uint32_t pin) { 80 return ZX_ERR_NOT_SUPPORTED; 81} 82 83static zx_status_t hi3660_gpio_set_polarity(void* ctx, uint32_t pin, uint32_t polarity) { 84 return ZX_ERR_NOT_SUPPORTED; 85} 86 87static gpio_impl_protocol_ops_t gpio_ops = { 88 .config_in = hi3660_gpio_config_in, 89 .config_out = hi3660_gpio_config_out, 90 .set_alt_function = hi3660_gpio_set_alt_function, 91 .read = hi3660_gpio_read, 92 .write = hi3660_gpio_write, 93 .get_interrupt = hi3660_gpio_get_interrupt, 94 .release_interrupt = hi3660_gpio_release_interrupt, 95 .set_polarity = hi3660_gpio_set_polarity, 96}; 97 98typedef struct { 99 zx_paddr_t base; 100 size_t length; 101 uint32_t start_pin; 102 uint32_t pin_count; 103 const uint32_t* irqs; 104 uint32_t irq_count; 105} gpio_block_t; 106 107static const uint32_t irqs_0[] = { 108 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 109}; 110 111static const uint32_t irqs_18[] = { 112 134, 135, 113}; 114 115static const uint32_t irqs_20[] = { 116 136, 137, 117}; 118 119static const uint32_t irqs_22[] = { 120 138, 139, 140, 141, 142, 143, 121}; 122 123static const uint32_t irqs_28[] = { 124 173, 125}; 126 127static const gpio_block_t gpio_blocks[] = { 128 { 129 // GPIO groups 0 - 17 130 .base = GPIO_0_ADDR, 131 .length = 18 * 4096, 132 .start_pin = 0, 133 .pin_count = 18 * 8, 134 .irqs = irqs_0, 135 .irq_count = countof(irqs_0), 136 }, 137 { 138 // GPIO groups 18 and 19 139 .base = GPIO_18_ADDR, 140 .length = 2 * 4096, 141 .start_pin = 18 * 8, 142 .pin_count = 2 * 8, 143 .irqs = irqs_18, 144 .irq_count = countof(irqs_18), 145 }, 146 { 147 // GPIO groups 20 and 21 148 .base = GPIO_20_ADDR, 149 .length = 2 * 4096, 150 .start_pin = 20 * 8, 151 .pin_count = 2 * 8, 152 .irqs = irqs_20, 153 .irq_count = countof(irqs_20), 154 }, 155 { 156 // GPIO groups 22 - 27 157 .base = GPIO_22_ADDR, 158 .length = 6 * 4096, 159 .start_pin = 22 * 8, 160 .pin_count = 6 * 8, 161 .irqs = irqs_22, 162 .irq_count = countof(irqs_22), 163 }, 164 { 165 // GPIO group 28 166 .base = GPIO_28_ADDR, 167 .length = 1 * 4096, 168 .start_pin = 28 * 8, 169 .pin_count = 1 * 8, 170 .irqs = irqs_28, 171 .irq_count = countof(irqs_28), 172 }, 173}; 174 175zx_status_t hi3660_gpio_init(hi3660_t* hi3660, zx_handle_t bti) { 176 zx_status_t status; 177 zx_handle_t resource = get_root_resource(); 178 179 for (size_t i = 0; i < countof(gpio_blocks); i++) { 180 const gpio_block_t* block = &gpio_blocks[i]; 181 182 pl061_gpios_t* gpios = calloc(1, sizeof(pl061_gpios_t)); 183 if (!gpios) { 184 return ZX_ERR_NO_MEMORY; 185 } 186 187 status = io_buffer_init_physical(&gpios->buffer, bti, block->base, block->length, 188 resource, ZX_CACHE_POLICY_UNCACHED_DEVICE); 189 if (status != ZX_OK) { 190 zxlogf(ERROR, "hi3660_gpio_init: io_buffer_init_physical failed %d\n", status); 191 free(gpios); 192 return status; 193 } 194 195 mtx_init(&gpios->lock, mtx_plain); 196 gpios->gpio_start = block->start_pin; 197 gpios->gpio_count = block->pin_count; 198 gpios->irqs = block->irqs; 199 gpios->irq_count = block->irq_count; 200 list_add_tail(&hi3660->gpios, &gpios->node); 201 } 202 203 hi3660->gpio.ops = &gpio_ops; 204 hi3660->gpio.ctx = hi3660; 205 206 return ZX_OK; 207} 208 209void hi3660_gpio_release(hi3660_t* hi3660) { 210 pl061_gpios_t* gpios; 211 212 while ((gpios = list_remove_head_type(&hi3660->gpios, pl061_gpios_t, node)) != NULL) { 213 io_buffer_release(&gpios->buffer); 214 free(gpios); 215 } 216} 217