1 /* 2 * Timer/counter unit support. 3 * 4 * Copyright (C) 2024 Paul Boddie <paul@boddie.org.uk> 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License as 8 * published by the Free Software Foundation; either version 2 of 9 * the License, or (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 * Boston, MA 02110-1301, USA 20 */ 21 22 #include "tcu-x1600.h" 23 24 25 26 // Register locations. 27 28 enum Regs : unsigned 29 { 30 Tcu_control_base = 0x04c, // TCRn 31 32 // Block size/step/offset for the above register set. 33 34 Tcu_data_block_offset = 0x010, 35 }; 36 37 enum Regs_x1600 : unsigned 38 { 39 // X1600 channel-related locations. 40 41 Tcu_store_flag_status = 0x200, // TSFR 42 Tcu_store_set_flag = 0x204, // TSFSR 43 Tcu_store_clear_flag = 0x208, // TSFCR 44 Tcu_store_mask_status = 0x210, // TSMR 45 Tcu_store_set_mask = 0x214, // TSMSR 46 Tcu_store_clear_mask = 0x218, // TSMCR 47 48 Tcu_capture_control_base = 0x0c0, // TCRn 49 Tcu_capture_counter_base = 0x0e0, // CAPVRn 50 Tcu_filter_value_base = 0x1a0, // FIRVRn 51 Tcu_stored_counter_base = 0x220, // TSVRn 52 Tcu_stored_filter_counter_base = 0x240, // TSFVRn 53 54 // Block size/step/offset for the above register set. 55 56 Tcu_capture_block_offset = 0x004, 57 58 // Limits. 59 60 Tcu_capture_channel_max = 3, 61 }; 62 63 // Field definitions. 64 65 // Counter data constraints. 66 67 enum Data_masks : unsigned 68 { 69 Data_mask = 0xffff, 70 }; 71 72 enum Control_bits_x1600 : unsigned 73 { 74 Store_negative_edge_enable = 0x04000000, // STORE_NEG_EN 75 Store_positive_edge_enable = 0x02000000, // STORE_POS_EN 76 Store_enable = 0x01000000, // STORE_EN 77 78 Count_mode_field_mask = 0x3, // COUNT_MODE 79 Count_mode_wrap_at_full_data = 0, 80 Count_mode_wrap_at_field_limit = 1, 81 Count_mode_stop_at_field_limit = 2, 82 Count_mode_field_shift = 22, 83 84 Count_source_field_mask = 0x3f, 85 Count_gpio1_negative_edge_enable = 0x20, // GPIO1_NEG_EN 86 Count_gpio1_positive_edge_enable = 0x10, // GPIO1_POS_EN 87 Count_gpio0_negative_edge_enable = 0x08, // GPIO0_NEG_EN 88 Count_gpio0_positive_edge_enable = 0x04, // GPIO0_POS_EN 89 Count_clock_negative_edge_enable = 0x02, // CLK_NEG_EN 90 Count_clock_positive_edge_enable = 0x01, // CLK_POS_EN 91 Count_source_field_shift = 16, 92 93 Count_shutdown = 0x00008000, // SHUTDOWN 94 Count_gate_polarity_low = 0x00000000, // GATE_POLA = 0 95 Count_gate_polarity_high = 0x00004000, // GATE_POLA = 1 96 Count_direction_polarity_low = 0x00000000, // DIRECTION_POLA = 0 97 Count_direction_polarity_high = 0x00002000, // DIRECTION_POLA = 1 98 99 Count_gate_select_field_mask = 0x3, // GATE_SEL 100 Count_gate_select_none = 0, 101 Count_gate_select_clock = 1, 102 Count_gate_select_gpio0 = 2, 103 Count_gate_select_gpio1 = 3, 104 Count_gate_select_field_shift = 11, 105 106 Count_direction_select_field_mask = 0x7, // DIRECTION_SEL 107 Count_direction_select_none = 0, 108 Count_direction_select_clock = 1, 109 Count_direction_select_gpio0 = 2, 110 Count_direction_select_gpio1 = 3, 111 Count_direction_select_gpio01 = 4, 112 Count_direction_select_field_shift = 8, 113 114 Count_gpio1_enable = 0x00000080, // GPIO1_EN 115 Count_gpio0_enable = 0x00000040, // GPIO0_EN 116 }; 117 118 enum Capture_bits : unsigned 119 { 120 Capture_select_mask = 0x00070000, // CAPTURE_SEL 121 Capture_select_clock = 0x00000000, // CAPTURE_SEL = 0 122 Capture_select_gpio0 = 0x00010000, // CAPTURE_SEL = 1 123 Capture_select_gpio1 = 0x00020000, // CAPTURE_SEL = 2 124 Capture_count_mask = 0x000000ff, // CAPTURE_NUM 125 }; 126 127 enum Capture_value_bits : unsigned 128 { 129 Capture_time_all_mask = 0xffff0000, // CAPTURE_ALL 130 Capture_time_high_mask = 0x0000ffff, // CAPTURE_HEIGHT (sic) 131 }; 132 133 enum Filter_value_bits : unsigned 134 { 135 Filter_gpio1_value_mask = 0x03ff0000, // FIL_B 136 Filter_gpio0_value_mask = 0x000003ff, // FIL_A 137 }; 138 139 enum Store_filter_bits : unsigned 140 { 141 Store_filter_value_mask = 0x3ff, // STR_FIL 142 }; 143 144 145 146 // Channel abstraction. 147 148 Tcu_x1600_channel::Tcu_x1600_channel(l4_addr_t addr, uint8_t channel, 149 l4_cap_idx_t irq) 150 : Tcu_channel(addr, channel, irq) 151 { 152 } 153 154 // Operation methods. 155 156 void 157 Tcu_x1600_channel::enable() 158 { 159 // NOTE: Use a positive clock edge for the timer event by default. 160 161 set_field(Tcu_control_base + _channel * Tcu_data_block_offset, 162 Count_source_field_mask, Count_source_field_shift, 163 Count_clock_positive_edge_enable); 164 165 Tcu_channel::enable(); 166 } 167 168 uint8_t 169 Tcu_x1600_channel::get_count_mode() 170 { 171 return get_field(Tcu_control_base + _channel * Tcu_data_block_offset, 172 Count_mode_field_mask, Count_mode_field_shift); 173 } 174 175 void 176 Tcu_x1600_channel::set_count_mode(uint8_t mode) 177 { 178 set_field(Tcu_control_base + _channel * Tcu_data_block_offset, 179 Count_mode_field_mask, Count_mode_field_shift, mode); 180 } 181 182 183 184 // Peripheral abstraction. 185 186 Tcu_x1600_chip::Tcu_x1600_chip(l4_addr_t start, l4_addr_t end) 187 : Tcu_chip(start, end) 188 { 189 } 190 191 Tcu_channel *Tcu_x1600_chip::_get_channel(l4_addr_t addr, uint8_t channel, 192 l4_cap_idx_t irq) 193 { 194 return new Tcu_x1600_channel(addr, channel, irq); 195 } 196 197 198 199 // C language interface functions. 200 201 void *x1600_tcu_init(l4_addr_t tcu_base, l4_addr_t tcu_base_end) 202 { 203 return (void *) new Tcu_x1600_chip(tcu_base, tcu_base_end); 204 } 205 206 void *x1600_tcu_get_channel(void *tcu, uint8_t channel, l4_cap_idx_t irq) 207 { 208 return static_cast<Tcu_x1600_chip *>(tcu)->get_channel(channel, irq); 209 } 210 211 void x1600_tcu_disable(void *tcu_channel) 212 { 213 static_cast<Tcu_x1600_channel *>(tcu_channel)->disable(); 214 } 215 216 void x1600_tcu_enable(void *tcu_channel) 217 { 218 static_cast<Tcu_x1600_channel *>(tcu_channel)->enable(); 219 } 220 221 int x1600_tcu_is_enabled(void *tcu_channel) 222 { 223 return static_cast<Tcu_x1600_channel *>(tcu_channel)->is_enabled(); 224 } 225 226 uint8_t x1600_tcu_get_clock(void *tcu_channel) 227 { 228 return static_cast<Tcu_x1600_channel *>(tcu_channel)->get_clock(); 229 } 230 231 void x1600_tcu_set_clock(void *tcu_channel, uint8_t clock) 232 { 233 static_cast<Tcu_x1600_channel *>(tcu_channel)->set_clock(clock); 234 } 235 236 uint32_t x1600_tcu_get_prescale(void *tcu_channel) 237 { 238 return static_cast<Tcu_x1600_channel *>(tcu_channel)->get_prescale(); 239 } 240 241 void x1600_tcu_set_prescale(void *tcu_channel, uint32_t prescale) 242 { 243 static_cast<Tcu_x1600_channel *>(tcu_channel)->set_prescale(prescale); 244 } 245 246 uint32_t x1600_tcu_get_counter(void *tcu_channel) 247 { 248 return static_cast<Tcu_x1600_channel *>(tcu_channel)->get_counter(); 249 } 250 251 void x1600_tcu_set_counter(void *tcu_channel, uint32_t value) 252 { 253 static_cast<Tcu_x1600_channel *>(tcu_channel)->set_counter(value); 254 } 255 256 uint8_t x1600_tcu_get_count_mode(void *tcu_channel) 257 { 258 return static_cast<Tcu_x1600_channel *>(tcu_channel)->get_count_mode(); 259 } 260 261 void x1600_tcu_set_count_mode(void *tcu_channel, uint8_t mode) 262 { 263 static_cast<Tcu_x1600_channel *>(tcu_channel)->set_count_mode(mode); 264 } 265 266 uint32_t x1600_tcu_get_full_data_value(void *tcu_channel) 267 { 268 return static_cast<Tcu_x1600_channel *>(tcu_channel)->get_full_data_value(); 269 } 270 271 void x1600_tcu_set_full_data_value(void *tcu_channel, uint32_t value) 272 { 273 static_cast<Tcu_x1600_channel *>(tcu_channel)->set_full_data_value(value); 274 } 275 276 uint32_t x1600_tcu_get_half_data_value(void *tcu_channel) 277 { 278 return static_cast<Tcu_x1600_channel *>(tcu_channel)->get_half_data_value(); 279 } 280 281 void x1600_tcu_set_half_data_value(void *tcu_channel, uint32_t value) 282 { 283 static_cast<Tcu_x1600_channel *>(tcu_channel)->set_full_data_value(value); 284 } 285 286 int x1600_tcu_get_full_data_mask(void *tcu_channel) 287 { 288 return static_cast<Tcu_x1600_channel *>(tcu_channel)->get_full_data_mask(); 289 } 290 291 void x1600_tcu_set_full_data_mask(void *tcu_channel, int masked) 292 { 293 static_cast<Tcu_x1600_channel *>(tcu_channel)->set_full_data_mask(masked); 294 } 295 296 int x1600_tcu_get_half_data_mask(void *tcu_channel) 297 { 298 return static_cast<Tcu_x1600_channel *>(tcu_channel)->get_half_data_mask(); 299 } 300 301 void x1600_tcu_set_half_data_mask(void *tcu_channel, int masked) 302 { 303 static_cast<Tcu_x1600_channel *>(tcu_channel)->set_half_data_mask(masked); 304 } 305 306 int x1600_tcu_have_interrupt(void *tcu_channel) 307 { 308 return static_cast<Tcu_x1600_channel *>(tcu_channel)->have_interrupt(); 309 } 310 311 int x1600_tcu_wait_for_irq(void *tcu_channel, unsigned int timeout) 312 { 313 return static_cast<Tcu_x1600_channel *>(tcu_channel)->wait_for_irq(timeout); 314 }