1/* Blackfin Parallel Port Interface (PPI) model 2 For "old style" PPIs on BF53x/etc... parts. 3 4 Copyright (C) 2010-2023 Free Software Foundation, Inc. 5 Contributed by Analog Devices, Inc. 6 7 This file is part of simulators. 8 9 This program is free software; you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation; either version 3 of the License, or 12 (at your option) any later version. 13 14 This program is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 21 22/* This must come before any other includes. */ 23#include "defs.h" 24 25#include "sim-main.h" 26#include "devices.h" 27#include "dv-bfin_ppi.h" 28#include "gui.h" 29 30/* XXX: TX is merely a stub. */ 31 32struct bfin_ppi 33{ 34 /* This top portion matches common dv_bfin struct. */ 35 bu32 base; 36 struct hw *dma_master; 37 bool acked; 38 39 struct hw_event *handler; 40 char saved_byte; 41 int saved_count; 42 43 /* GUI state. */ 44 void *gui_state; 45 int color; 46 47 /* Order after here is important -- matches hardware MMR layout. */ 48 bu16 BFIN_MMR_16(control); 49 bu16 BFIN_MMR_16(status); 50 bu16 BFIN_MMR_16(count); 51 bu16 BFIN_MMR_16(delay); 52 bu16 BFIN_MMR_16(frame); 53}; 54#define mmr_base() offsetof(struct bfin_ppi, control) 55#define mmr_offset(mmr) (offsetof(struct bfin_ppi, mmr) - mmr_base()) 56 57static const char * const mmr_names[] = 58{ 59 "PPI_CONTROL", "PPI_STATUS", "PPI_COUNT", "PPI_DELAY", "PPI_FRAME", 60}; 61#define mmr_name(off) mmr_names[(off) / 4] 62 63static void 64bfin_ppi_gui_setup (struct bfin_ppi *ppi) 65{ 66 int bpp; 67 68 /* If we are in RX mode, nothing to do. */ 69 if (!(ppi->control & PORT_DIR)) 70 return; 71 72 bpp = bfin_gui_color_depth (ppi->color); 73 ppi->gui_state = bfin_gui_setup (ppi->gui_state, 74 ppi->control & PORT_EN, 75 (ppi->count + 1) / (bpp / 8), 76 ppi->frame, 77 ppi->color); 78} 79 80static unsigned 81bfin_ppi_io_write_buffer (struct hw *me, const void *source, int space, 82 address_word addr, unsigned nr_bytes) 83{ 84 struct bfin_ppi *ppi = hw_data (me); 85 bu32 mmr_off; 86 bu32 value; 87 bu16 *valuep; 88 89 /* Invalid access mode is higher priority than missing register. */ 90 if (!dv_bfin_mmr_require_16 (me, addr, nr_bytes, true)) 91 return 0; 92 93 value = dv_load_2 (source); 94 mmr_off = addr - ppi->base; 95 valuep = (void *)((uintptr_t)ppi + mmr_base() + mmr_off); 96 97 HW_TRACE_WRITE (); 98 99 switch (mmr_off) 100 { 101 case mmr_offset(control): 102 *valuep = value; 103 bfin_ppi_gui_setup (ppi); 104 break; 105 case mmr_offset(count): 106 case mmr_offset(delay): 107 case mmr_offset(frame): 108 *valuep = value; 109 break; 110 case mmr_offset(status): 111 dv_w1c_2 (valuep, value, ~(1 << 10)); 112 break; 113 default: 114 dv_bfin_mmr_invalid (me, addr, nr_bytes, true); 115 return 0; 116 } 117 118 return nr_bytes; 119} 120 121static unsigned 122bfin_ppi_io_read_buffer (struct hw *me, void *dest, int space, 123 address_word addr, unsigned nr_bytes) 124{ 125 struct bfin_ppi *ppi = hw_data (me); 126 bu32 mmr_off; 127 bu16 *valuep; 128 129 /* Invalid access mode is higher priority than missing register. */ 130 if (!dv_bfin_mmr_require_16 (me, addr, nr_bytes, false)) 131 return 0; 132 133 mmr_off = addr - ppi->base; 134 valuep = (void *)((uintptr_t)ppi + mmr_base() + mmr_off); 135 136 HW_TRACE_READ (); 137 138 switch (mmr_off) 139 { 140 case mmr_offset(control): 141 case mmr_offset(count): 142 case mmr_offset(delay): 143 case mmr_offset(frame): 144 case mmr_offset(status): 145 dv_store_2 (dest, *valuep); 146 break; 147 default: 148 dv_bfin_mmr_invalid (me, addr, nr_bytes, false); 149 return 0; 150 } 151 152 return nr_bytes; 153} 154 155static unsigned 156bfin_ppi_dma_read_buffer (struct hw *me, void *dest, int space, 157 unsigned_word addr, unsigned nr_bytes) 158{ 159 HW_TRACE_DMA_READ (); 160 return 0; 161} 162 163static unsigned 164bfin_ppi_dma_write_buffer (struct hw *me, const void *source, 165 int space, unsigned_word addr, 166 unsigned nr_bytes, 167 int violate_read_only_section) 168{ 169 struct bfin_ppi *ppi = hw_data (me); 170 171 HW_TRACE_DMA_WRITE (); 172 173 return bfin_gui_update (ppi->gui_state, source, nr_bytes); 174} 175 176static const struct hw_port_descriptor bfin_ppi_ports[] = 177{ 178 { "stat", 0, 0, output_port, }, 179 { NULL, 0, 0, 0, }, 180}; 181 182static void 183attach_bfin_ppi_regs (struct hw *me, struct bfin_ppi *ppi) 184{ 185 address_word attach_address; 186 int attach_space; 187 unsigned attach_size; 188 reg_property_spec reg; 189 190 if (hw_find_property (me, "reg") == NULL) 191 hw_abort (me, "Missing \"reg\" property"); 192 193 if (!hw_find_reg_array_property (me, "reg", 0, ®)) 194 hw_abort (me, "\"reg\" property must contain three addr/size entries"); 195 196 hw_unit_address_to_attach_address (hw_parent (me), 197 ®.address, 198 &attach_space, &attach_address, me); 199 hw_unit_size_to_attach_size (hw_parent (me), ®.size, &attach_size, me); 200 201 if (attach_size != BFIN_MMR_PPI_SIZE) 202 hw_abort (me, "\"reg\" size must be %#x", BFIN_MMR_PPI_SIZE); 203 204 hw_attach_address (hw_parent (me), 205 0, attach_space, attach_address, attach_size, me); 206 207 ppi->base = attach_address; 208} 209 210static void 211bfin_ppi_finish (struct hw *me) 212{ 213 struct bfin_ppi *ppi; 214 const char *color; 215 216 ppi = HW_ZALLOC (me, struct bfin_ppi); 217 218 set_hw_data (me, ppi); 219 set_hw_io_read_buffer (me, bfin_ppi_io_read_buffer); 220 set_hw_io_write_buffer (me, bfin_ppi_io_write_buffer); 221 set_hw_dma_read_buffer (me, bfin_ppi_dma_read_buffer); 222 set_hw_dma_write_buffer (me, bfin_ppi_dma_write_buffer); 223 set_hw_ports (me, bfin_ppi_ports); 224 225 attach_bfin_ppi_regs (me, ppi); 226 227 /* Initialize the PPI. */ 228 if (hw_find_property (me, "color")) 229 color = hw_find_string_property (me, "color"); 230 else 231 color = NULL; 232 ppi->color = bfin_gui_color (color); 233} 234 235const struct hw_descriptor dv_bfin_ppi_descriptor[] = 236{ 237 {"bfin_ppi", bfin_ppi_finish,}, 238 {NULL, NULL}, 239}; 240