1 /* Blackfin Two Wire Interface (TWI) model 2 3 Copyright (C) 2010-2023 Free Software Foundation, Inc. 4 Contributed by Analog Devices, Inc. 5 6 This file is part of simulators. 7 8 This program is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 3 of the License, or 11 (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 20 21 /* This must come before any other includes. */ 22 #include "defs.h" 23 24 #include "sim-main.h" 25 #include "devices.h" 26 #include "dv-bfin_twi.h" 27 28 /* XXX: This is merely a stub. */ 29 30 struct bfin_twi 31 { 32 /* This top portion matches common dv_bfin struct. */ 33 bu32 base; 34 struct hw *dma_master; 35 bool acked; 36 37 struct hw_event *handler; 38 char saved_byte; 39 int saved_count; 40 41 bu16 xmt_fifo, rcv_fifo; 42 43 /* Order after here is important -- matches hardware MMR layout. */ 44 bu16 BFIN_MMR_16(clkdiv); 45 bu16 BFIN_MMR_16(control); 46 bu16 BFIN_MMR_16(slave_ctl); 47 bu16 BFIN_MMR_16(slave_stat); 48 bu16 BFIN_MMR_16(slave_addr); 49 bu16 BFIN_MMR_16(master_ctl); 50 bu16 BFIN_MMR_16(master_stat); 51 bu16 BFIN_MMR_16(master_addr); 52 bu16 BFIN_MMR_16(int_stat); 53 bu16 BFIN_MMR_16(int_mask); 54 bu16 BFIN_MMR_16(fifo_ctl); 55 bu16 BFIN_MMR_16(fifo_stat); 56 bu32 _pad0[20]; 57 bu16 BFIN_MMR_16(xmt_data8); 58 bu16 BFIN_MMR_16(xmt_data16); 59 bu16 BFIN_MMR_16(rcv_data8); 60 bu16 BFIN_MMR_16(rcv_data16); 61 }; 62 #define mmr_base() offsetof(struct bfin_twi, clkdiv) 63 #define mmr_offset(mmr) (offsetof(struct bfin_twi, mmr) - mmr_base()) 64 #define mmr_idx(mmr) (mmr_offset (mmr) / 4) 65 66 static const char * const mmr_names[] = 67 { 68 "TWI_CLKDIV", "TWI_CONTROL", "TWI_SLAVE_CTL", "TWI_SLAVE_STAT", 69 "TWI_SLAVE_ADDR", "TWI_MASTER_CTL", "TWI_MASTER_STAT", "TWI_MASTER_ADDR", 70 "TWI_INT_STAT", "TWI_INT_MASK", "TWI_FIFO_CTL", "TWI_FIFO_STAT", 71 [mmr_idx (xmt_data8)] = "TWI_XMT_DATA8", "TWI_XMT_DATA16", "TWI_RCV_DATA8", 72 "TWI_RCV_DATA16", 73 }; 74 #define mmr_name(off) (mmr_names[(off) / 4] ? : "<INV>") 75 76 static unsigned 77 bfin_twi_io_write_buffer (struct hw *me, const void *source, int space, 78 address_word addr, unsigned nr_bytes) 79 { 80 struct bfin_twi *twi = hw_data (me); 81 bu32 mmr_off; 82 bu32 value; 83 bu16 *valuep; 84 85 /* Invalid access mode is higher priority than missing register. */ 86 if (!dv_bfin_mmr_require_16 (me, addr, nr_bytes, true)) 87 return 0; 88 89 value = dv_load_2 (source); 90 mmr_off = addr - twi->base; 91 valuep = (void *)((uintptr_t)twi + mmr_base() + mmr_off); 92 93 HW_TRACE_WRITE (); 94 95 switch (mmr_off) 96 { 97 case mmr_offset(clkdiv): 98 case mmr_offset(control): 99 case mmr_offset(slave_ctl): 100 case mmr_offset(slave_addr): 101 case mmr_offset(master_ctl): 102 case mmr_offset(master_addr): 103 case mmr_offset(int_mask): 104 case mmr_offset(fifo_ctl): 105 *valuep = value; 106 break; 107 case mmr_offset(int_stat): 108 dv_w1c_2 (valuep, value, -1); 109 break; 110 case mmr_offset(master_stat): 111 dv_w1c_2 (valuep, value, BUFWRERR | BUFRDERR | DNAK | ANAK | LOSTARB); 112 break; 113 case mmr_offset(slave_stat): 114 case mmr_offset(fifo_stat): 115 case mmr_offset(rcv_data8): 116 case mmr_offset(rcv_data16): 117 /* These are all RO. XXX: Does these throw error ? */ 118 break; 119 case mmr_offset(xmt_data8): 120 value &= 0xff; 121 case mmr_offset(xmt_data16): 122 twi->xmt_fifo = value; 123 break; 124 default: 125 dv_bfin_mmr_invalid (me, addr, nr_bytes, true); 126 return 0; 127 } 128 129 return nr_bytes; 130 } 131 132 static unsigned 133 bfin_twi_io_read_buffer (struct hw *me, void *dest, int space, 134 address_word addr, unsigned nr_bytes) 135 { 136 struct bfin_twi *twi = hw_data (me); 137 bu32 mmr_off; 138 bu16 *valuep; 139 140 /* Invalid access mode is higher priority than missing register. */ 141 if (!dv_bfin_mmr_require_16 (me, addr, nr_bytes, false)) 142 return 0; 143 144 mmr_off = addr - twi->base; 145 valuep = (void *)((uintptr_t)twi + mmr_base() + mmr_off); 146 147 HW_TRACE_READ (); 148 149 switch (mmr_off) 150 { 151 case mmr_offset(clkdiv): 152 case mmr_offset(control): 153 case mmr_offset(slave_ctl): 154 case mmr_offset(slave_stat): 155 case mmr_offset(slave_addr): 156 case mmr_offset(master_ctl): 157 case mmr_offset(master_stat): 158 case mmr_offset(master_addr): 159 case mmr_offset(int_stat): 160 case mmr_offset(int_mask): 161 case mmr_offset(fifo_ctl): 162 case mmr_offset(fifo_stat): 163 dv_store_2 (dest, *valuep); 164 break; 165 case mmr_offset(rcv_data8): 166 case mmr_offset(rcv_data16): 167 dv_store_2 (dest, twi->rcv_fifo); 168 break; 169 case mmr_offset(xmt_data8): 170 case mmr_offset(xmt_data16): 171 /* These always read as 0. */ 172 dv_store_2 (dest, 0); 173 break; 174 default: 175 dv_bfin_mmr_invalid (me, addr, nr_bytes, false); 176 return 0; 177 } 178 179 return nr_bytes; 180 } 181 182 static const struct hw_port_descriptor bfin_twi_ports[] = 183 { 184 { "stat", 0, 0, output_port, }, 185 { NULL, 0, 0, 0, }, 186 }; 187 188 static void 189 attach_bfin_twi_regs (struct hw *me, struct bfin_twi *twi) 190 { 191 address_word attach_address; 192 int attach_space; 193 unsigned attach_size; 194 reg_property_spec reg; 195 196 if (hw_find_property (me, "reg") == NULL) 197 hw_abort (me, "Missing \"reg\" property"); 198 199 if (!hw_find_reg_array_property (me, "reg", 0, ®)) 200 hw_abort (me, "\"reg\" property must contain three addr/size entries"); 201 202 hw_unit_address_to_attach_address (hw_parent (me), 203 ®.address, 204 &attach_space, &attach_address, me); 205 hw_unit_size_to_attach_size (hw_parent (me), ®.size, &attach_size, me); 206 207 if (attach_size != BFIN_MMR_TWI_SIZE) 208 hw_abort (me, "\"reg\" size must be %#x", BFIN_MMR_TWI_SIZE); 209 210 hw_attach_address (hw_parent (me), 211 0, attach_space, attach_address, attach_size, me); 212 213 twi->base = attach_address; 214 } 215 216 static void 217 bfin_twi_finish (struct hw *me) 218 { 219 struct bfin_twi *twi; 220 221 twi = HW_ZALLOC (me, struct bfin_twi); 222 223 set_hw_data (me, twi); 224 set_hw_io_read_buffer (me, bfin_twi_io_read_buffer); 225 set_hw_io_write_buffer (me, bfin_twi_io_write_buffer); 226 set_hw_ports (me, bfin_twi_ports); 227 228 attach_bfin_twi_regs (me, twi); 229 } 230 231 const struct hw_descriptor dv_bfin_twi_descriptor[] = 232 { 233 {"bfin_twi", bfin_twi_finish,}, 234 {NULL, NULL}, 235 }; 236