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 // Flag/mask register bits. 66 67 enum Flag_bit_numbers : unsigned 68 { 69 Half_match_wdt = 24, // HFLAGW 70 71 // Flag/mask group bit offsets. 72 73 Half_match_shift = 16, 74 Full_match_shift = 0, 75 }; 76 77 // Counter data constraints. 78 79 enum Data_masks : unsigned 80 { 81 Data_mask = 0xffff, 82 }; 83 84 enum Control_bits_x1600 : unsigned 85 { 86 Store_negative_edge_enable = 0x04000000, // STORE_NEG_EN 87 Store_positive_edge_enable = 0x02000000, // STORE_POS_EN 88 Store_enable = 0x01000000, // STORE_EN 89 90 Count_mode_field_mask = 0x3, // COUNT_MODE 91 Count_mode_wrap_at_full_data = 0, 92 Count_mode_wrap_at_field_limit = 1, 93 Count_mode_stop_at_field_limit = 2, 94 Count_mode_field_shift = 22, 95 96 Count_source_field_mask = 0x3f, 97 Count_gpio1_negative_edge_enable = 0x20, // GPIO1_NEG_EN 98 Count_gpio1_positive_edge_enable = 0x10, // GPIO1_POS_EN 99 Count_gpio0_negative_edge_enable = 0x08, // GPIO0_NEG_EN 100 Count_gpio0_positive_edge_enable = 0x04, // GPIO0_POS_EN 101 Count_clock_negative_edge_enable = 0x02, // CLK_NEG_EN 102 Count_clock_positive_edge_enable = 0x01, // CLK_POS_EN 103 Count_source_field_shift = 16, 104 105 Count_shutdown = 0x00008000, // SHUTDOWN 106 Count_gate_polarity_low = 0x00000000, // GATE_POLA = 0 107 Count_gate_polarity_high = 0x00004000, // GATE_POLA = 1 108 Count_direction_polarity_low = 0x00000000, // DIRECTION_POLA = 0 109 Count_direction_polarity_high = 0x00002000, // DIRECTION_POLA = 1 110 111 Count_gate_select_field_mask = 0x3, // GATE_SEL 112 Count_gate_select_none = 0, 113 Count_gate_select_clock = 1, 114 Count_gate_select_gpio0 = 2, 115 Count_gate_select_gpio1 = 3, 116 Count_gate_select_field_shift = 11, 117 118 Count_direction_select_field_mask = 0x7, // DIRECTION_SEL 119 Count_direction_select_none = 0, 120 Count_direction_select_clock = 1, 121 Count_direction_select_gpio0 = 2, 122 Count_direction_select_gpio1 = 3, 123 Count_direction_select_gpio01 = 4, 124 Count_direction_select_field_shift = 8, 125 126 Count_gpio1_enable = 0x00000080, // GPIO1_EN 127 Count_gpio0_enable = 0x00000040, // GPIO0_EN 128 }; 129 130 enum Capture_bits : unsigned 131 { 132 Capture_select_mask = 0x00070000, // CAPTURE_SEL 133 Capture_select_clock = 0x00000000, // CAPTURE_SEL = 0 134 Capture_select_gpio0 = 0x00010000, // CAPTURE_SEL = 1 135 Capture_select_gpio1 = 0x00020000, // CAPTURE_SEL = 2 136 Capture_count_mask = 0x000000ff, // CAPTURE_NUM 137 }; 138 139 enum Capture_value_bits : unsigned 140 { 141 Capture_time_all_mask = 0xffff0000, // CAPTURE_ALL 142 Capture_time_high_mask = 0x0000ffff, // CAPTURE_HEIGHT (sic) 143 }; 144 145 enum Filter_value_bits : unsigned 146 { 147 Filter_gpio1_value_mask = 0x03ff0000, // FIL_B 148 Filter_gpio0_value_mask = 0x000003ff, // FIL_A 149 }; 150 151 enum Store_filter_bits : unsigned 152 { 153 Store_filter_value_mask = 0x3ff, // STR_FIL 154 }; 155 156 157 158 // Channel abstraction. 159 160 Tcu_x1600_channel::Tcu_x1600_channel(l4_addr_t addr, uint8_t channel) 161 : Tcu_channel(addr, channel) 162 { 163 } 164 165 // Operation methods. 166 167 void 168 Tcu_x1600_channel::enable() 169 { 170 // NOTE: Use a positive clock edge for the timer event by default. 171 172 set_field(Tcu_control_base + _channel * Tcu_data_block_offset, 173 Count_source_field_mask, Count_source_field_shift, 174 Count_clock_positive_edge_enable); 175 176 Tcu_channel::enable(); 177 } 178 179 uint8_t 180 Tcu_x1600_channel::get_count_mode() 181 { 182 return get_field(Tcu_control_base + _channel * Tcu_data_block_offset, 183 Count_mode_field_mask, Count_mode_field_shift); 184 } 185 186 void 187 Tcu_x1600_channel::set_count_mode(uint8_t mode) 188 { 189 set_field(Tcu_control_base + _channel * Tcu_data_block_offset, 190 Count_mode_field_mask, Count_mode_field_shift, mode); 191 } 192 193 194 195 // Peripheral abstraction. 196 197 Tcu_x1600_chip::Tcu_x1600_chip(l4_addr_t start, l4_addr_t end) 198 : Tcu_chip(start, end) 199 { 200 } 201 202 Tcu_channel *Tcu_x1600_chip::_get_channel(l4_addr_t addr, uint8_t channel) 203 { 204 return new Tcu_x1600_channel(addr, channel); 205 } 206 207 208 209 // C language interface functions. 210 211 void *x1600_tcu_init(l4_addr_t tcu_base, l4_addr_t tcu_base_end) 212 { 213 return (void *) new Tcu_x1600_chip(tcu_base, tcu_base_end); 214 } 215 216 void *x1600_tcu_get_channel(void *tcu, uint8_t channel) 217 { 218 return static_cast<Tcu_x1600_chip *>(tcu)->get_channel(channel); 219 } 220 221 void x1600_tcu_disable(void *tcu_channel) 222 { 223 static_cast<Tcu_x1600_channel *>(tcu_channel)->disable(); 224 } 225 226 void x1600_tcu_enable(void *tcu_channel) 227 { 228 static_cast<Tcu_x1600_channel *>(tcu_channel)->enable(); 229 } 230 231 int x1600_tcu_is_enabled(void *tcu_channel) 232 { 233 return static_cast<Tcu_x1600_channel *>(tcu_channel)->is_enabled(); 234 } 235 236 uint8_t x1600_tcu_get_clock(void *tcu_channel) 237 { 238 return static_cast<Tcu_x1600_channel *>(tcu_channel)->get_clock(); 239 } 240 241 void x1600_tcu_set_clock(void *tcu_channel, uint8_t clock) 242 { 243 static_cast<Tcu_x1600_channel *>(tcu_channel)->set_clock(clock); 244 } 245 246 uint32_t x1600_tcu_get_prescale(void *tcu_channel) 247 { 248 return static_cast<Tcu_x1600_channel *>(tcu_channel)->get_prescale(); 249 } 250 251 void x1600_tcu_set_prescale(void *tcu_channel, uint32_t prescale) 252 { 253 static_cast<Tcu_x1600_channel *>(tcu_channel)->set_prescale(prescale); 254 } 255 256 uint32_t x1600_tcu_get_counter(void *tcu_channel) 257 { 258 return static_cast<Tcu_x1600_channel *>(tcu_channel)->get_counter(); 259 } 260 261 void x1600_tcu_set_counter(void *tcu_channel, uint32_t value) 262 { 263 static_cast<Tcu_x1600_channel *>(tcu_channel)->set_counter(value); 264 } 265 266 uint8_t x1600_tcu_get_count_mode(void *tcu_channel) 267 { 268 return static_cast<Tcu_x1600_channel *>(tcu_channel)->get_count_mode(); 269 } 270 271 void x1600_tcu_set_count_mode(void *tcu_channel, uint8_t mode) 272 { 273 static_cast<Tcu_x1600_channel *>(tcu_channel)->set_count_mode(mode); 274 } 275 276 uint32_t x1600_tcu_get_full_data_value(void *tcu_channel) 277 { 278 return static_cast<Tcu_x1600_channel *>(tcu_channel)->get_full_data_value(); 279 } 280 281 void x1600_tcu_set_full_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 uint32_t x1600_tcu_get_half_data_value(void *tcu_channel) 287 { 288 return static_cast<Tcu_x1600_channel *>(tcu_channel)->get_half_data_value(); 289 } 290 291 void x1600_tcu_set_half_data_value(void *tcu_channel, uint32_t value) 292 { 293 static_cast<Tcu_x1600_channel *>(tcu_channel)->set_full_data_value(value); 294 }