1.1 --- a/pkg/devices/lib/cpm/src/x1600.cc Sat Sep 16 14:28:01 2023 +0200
1.2 +++ b/pkg/devices/lib/cpm/src/x1600.cc Sat Sep 16 16:53:06 2023 +0200
1.3 @@ -85,236 +85,6 @@
1.4
1.5
1.6
1.7 -// Register field abstraction.
1.8 -
1.9 -class Field
1.10 -{
1.11 - uint32_t reg;
1.12 - uint32_t mask;
1.13 - uint8_t bit;
1.14 - bool defined;
1.15 -
1.16 -public:
1.17 - explicit Field()
1.18 - : defined(false)
1.19 - {
1.20 - }
1.21 -
1.22 - explicit Field(uint32_t reg, uint32_t mask, uint32_t bit)
1.23 - : reg(reg), mask(mask), bit(bit), defined(true)
1.24 - {
1.25 - }
1.26 -
1.27 - uint32_t get_field(Cpm_regs ®s);
1.28 - void set_field(Cpm_regs ®s, uint32_t value);
1.29 - bool is_defined() { return defined; }
1.30 -};
1.31 -
1.32 -// Undefined fields.
1.33 -
1.34 -Field Gate_undefined, Change_enable_undefined, Busy_undefined, Divider_undefined;
1.35 -
1.36 -
1.37 -
1.38 -// Clock sources.
1.39 -
1.40 -class Mux
1.41 -{
1.42 - int _num_inputs;
1.43 - enum Clock_identifiers *_inputs, _input;
1.44 -
1.45 -public:
1.46 - explicit Mux(int num_inputs, enum Clock_identifiers inputs[])
1.47 - : _num_inputs(num_inputs), _inputs(inputs)
1.48 - {
1.49 - }
1.50 -
1.51 - explicit Mux(enum Clock_identifiers input)
1.52 - : _num_inputs(1), _inputs(&_input)
1.53 - {
1.54 - _input = input;
1.55 - }
1.56 -
1.57 - explicit Mux()
1.58 - : _num_inputs(0), _inputs(NULL)
1.59 - {
1.60 - }
1.61 -
1.62 - int get_number() { return _num_inputs; }
1.63 - enum Clock_identifiers get_input(int num);
1.64 -};
1.65 -
1.66 -class Source
1.67 -{
1.68 - Mux _inputs;
1.69 - Field _source;
1.70 -
1.71 -public:
1.72 - explicit Source(Mux inputs, Field source)
1.73 - : _inputs(inputs), _source(source)
1.74 - {
1.75 - }
1.76 -
1.77 - explicit Source(Mux inputs)
1.78 - : _inputs(inputs)
1.79 - {
1.80 - }
1.81 -
1.82 - explicit Source()
1.83 - {
1.84 - }
1.85 -
1.86 - int get_number() { return _inputs.get_number(); }
1.87 - enum Clock_identifiers get_input(int num) { return _inputs.get_input(num); }
1.88 -
1.89 - // Clock source.
1.90 -
1.91 - uint8_t get_source(Cpm_regs ®s);
1.92 - void set_source(Cpm_regs ®s, uint8_t source);
1.93 -
1.94 - // Clock source frequency.
1.95 -
1.96 - uint32_t get_frequency(Cpm_regs ®s);
1.97 -};
1.98 -
1.99 -// Undefined sources.
1.100 -
1.101 -Source Source_undefined;
1.102 -
1.103 -
1.104 -
1.105 -// Common clock abstraction.
1.106 -
1.107 -class Clock_base
1.108 -{
1.109 - Source _source;
1.110 -
1.111 -public:
1.112 - explicit Clock_base(Source source)
1.113 - : _source(source)
1.114 - {
1.115 - }
1.116 -
1.117 - // Clock control.
1.118 -
1.119 - virtual int have_clock(Cpm_regs ®s);
1.120 - virtual void start_clock(Cpm_regs ®s);
1.121 - virtual void stop_clock(Cpm_regs ®s);
1.122 -
1.123 - // Clock divider.
1.124 -
1.125 - virtual uint32_t get_divider(Cpm_regs ®s);
1.126 - virtual void set_divider(Cpm_regs ®s, uint32_t division);
1.127 -
1.128 - // Clock source.
1.129 -
1.130 - virtual uint8_t get_source(Cpm_regs ®s);
1.131 - virtual void set_source(Cpm_regs ®s, uint8_t source);
1.132 -
1.133 - // Clock source frequency.
1.134 -
1.135 - virtual uint32_t get_source_frequency(Cpm_regs ®s);
1.136 -
1.137 - // Output frequency.
1.138 -
1.139 - virtual uint32_t get_frequency(Cpm_regs ®s);
1.140 -};
1.141 -
1.142 -
1.143 -
1.144 -// PLL descriptions.
1.145 -
1.146 -class Pll : public Clock_base
1.147 -{
1.148 - Field _enable, _stable, _bypass;
1.149 - Field _multiplier, _input_division, _output_division0, _output_division1;
1.150 -
1.151 -public:
1.152 - explicit Pll(Source source,
1.153 - Field enable, Field stable, Field bypass,
1.154 - Field multiplier, Field input_division,
1.155 - Field output_division0, Field output_division1)
1.156 - : Clock_base(source),
1.157 - _enable(enable), _stable(stable), _bypass(bypass),
1.158 - _multiplier(multiplier), _input_division(input_division),
1.159 - _output_division0(output_division0), _output_division1(output_division1)
1.160 - {
1.161 - }
1.162 -
1.163 - // PLL_specific control.
1.164 -
1.165 - int have_pll(Cpm_regs ®s);
1.166 - int pll_enabled(Cpm_regs ®s);
1.167 - int pll_bypassed(Cpm_regs ®s);
1.168 -
1.169 - // Clock control.
1.170 -
1.171 - int have_clock(Cpm_regs ®s);
1.172 - void start_clock(Cpm_regs ®s);
1.173 - void stop_clock(Cpm_regs ®s);
1.174 -
1.175 - // General frequency modifiers.
1.176 -
1.177 - uint16_t get_multiplier(Cpm_regs ®s);
1.178 - void set_multiplier(Cpm_regs ®s, uint16_t multiplier);
1.179 - uint8_t get_input_division(Cpm_regs ®s);
1.180 - void set_input_division(Cpm_regs ®s, uint8_t divider);
1.181 - uint8_t get_output_division(Cpm_regs ®s);
1.182 - void set_output_division(Cpm_regs ®s, uint8_t divider);
1.183 -
1.184 - // PLL output frequency.
1.185 -
1.186 - uint32_t get_frequency(Cpm_regs ®s);
1.187 -
1.188 - // Other operations.
1.189 -
1.190 - void set_pll_parameters(Cpm_regs ®s, uint16_t multiplier,
1.191 - uint8_t in_divider, uint8_t out_divider);
1.192 -};
1.193 -
1.194 -
1.195 -
1.196 -// Clock descriptions.
1.197 -
1.198 -class Clock : public Clock_base
1.199 -{
1.200 - Field _gate, _change_enable, _busy, _divider;
1.201 -
1.202 - // Clock control.
1.203 -
1.204 - void change_disable(Cpm_regs ®s);
1.205 - void change_enable(Cpm_regs ®s);
1.206 - void wait_busy(Cpm_regs ®s);
1.207 -
1.208 -public:
1.209 - explicit Clock(Source source = Source_undefined,
1.210 - Field gate = Gate_undefined,
1.211 - Field change_enable = Change_enable_undefined,
1.212 - Field busy = Busy_undefined,
1.213 - Field divider = Divider_undefined)
1.214 - : Clock_base(source),
1.215 - _gate(gate), _change_enable(change_enable), _busy(busy), _divider(divider)
1.216 - {
1.217 - }
1.218 -
1.219 - // Clock control.
1.220 -
1.221 - int have_clock(Cpm_regs ®s);
1.222 - void start_clock(Cpm_regs ®s);
1.223 - void stop_clock(Cpm_regs ®s);
1.224 -
1.225 - // Clock divider.
1.226 -
1.227 - uint32_t get_divider(Cpm_regs ®s);
1.228 - void set_divider(Cpm_regs ®s, uint32_t division);
1.229 -
1.230 - // Clock source.
1.231 -
1.232 - void set_source(Cpm_regs ®s, uint8_t source);
1.233 -};
1.234 -
1.235 -
1.236 -
1.237 // Register field definitions.
1.238
1.239 Field Clock_source_main (Clock_control, 3, 30); // SEL_SRC (output to SCLK_A)
1.240 @@ -507,7 +277,7 @@
1.241 Clock_divider_cim);
1.242
1.243 Clock clock_cpu(Source(mux_core, Clock_source_cpu),
1.244 - Gate_undefined,
1.245 + Field::undefined,
1.246 Clock_change_enable_cpu,
1.247 Clock_busy_cpu,
1.248 Clock_divider_cpu);
1.249 @@ -527,13 +297,13 @@
1.250 Clock clock_hclock0(Source(mux_core, Clock_source_hclock0),
1.251 Clock_gate_ahb0,
1.252 Clock_change_enable_ahb0,
1.253 - Busy_undefined,
1.254 + Field::undefined,
1.255 Clock_divider_hclock0);
1.256
1.257 Clock clock_hclock2(Source(mux_ahb2_apb),
1.258 Clock_gate_apb0,
1.259 Clock_change_enable_ahb2,
1.260 - Busy_undefined,
1.261 + Field::undefined,
1.262 Clock_divider_hclock2);
1.263
1.264 Clock clock_hdmi;
1.265 @@ -595,8 +365,8 @@
1.266
1.267 Clock clock_pclock(Source(mux_ahb2_apb),
1.268 Clock_gate_apb0,
1.269 - Change_enable_undefined,
1.270 - Busy_undefined,
1.271 + Field::undefined,
1.272 + Field::undefined,
1.273 Clock_divider_pclock);
1.274
1.275 Pll clock_pll_A(Source(mux_external),
1.276 @@ -730,392 +500,12 @@
1.277
1.278
1.279
1.280 -// Register access.
1.281 -
1.282 -Cpm_regs::Cpm_regs(l4_addr_t addr, uint32_t exclk_freq)
1.283 -: exclk_freq(exclk_freq)
1.284 -{
1.285 - _regs = new Hw::Mmio_register_block<32>(addr);
1.286 -}
1.287 -
1.288 -// Utility methods.
1.289 -
1.290 -uint32_t
1.291 -Cpm_regs::get_field(uint32_t reg, uint32_t mask, uint8_t shift)
1.292 -{
1.293 - return (_regs[reg] & (mask << shift)) >> shift;
1.294 -}
1.295 -
1.296 -void
1.297 -Cpm_regs::set_field(uint32_t reg, uint32_t mask, uint8_t shift, uint32_t value)
1.298 -{
1.299 - _regs[reg] = (_regs[reg] & (~(mask << shift))) | ((mask & value) << shift);
1.300 -}
1.301 -
1.302 -
1.303 -
1.304 -// Field methods.
1.305 -
1.306 -uint32_t
1.307 -Field::get_field(Cpm_regs ®s)
1.308 -{
1.309 - if (defined)
1.310 - return regs.get_field(reg, mask, bit);
1.311 - else
1.312 - return 0;
1.313 -}
1.314 -
1.315 -void
1.316 -Field::set_field(Cpm_regs ®s, uint32_t value)
1.317 -{
1.318 - if (defined)
1.319 - regs.set_field(reg, mask, bit, value);
1.320 -}
1.321 -
1.322 -
1.323 -
1.324 -// Clock sources.
1.325 -
1.326 -enum Clock_identifiers
1.327 -Mux::get_input(int num)
1.328 -{
1.329 - if (num < _num_inputs)
1.330 - return _inputs[num];
1.331 - else
1.332 - return Clock_undefined;
1.333 -}
1.334 -
1.335 -// Clock sources.
1.336 -
1.337 -uint8_t
1.338 -Source::get_source(Cpm_regs ®s)
1.339 -{
1.340 - if (_source.is_defined())
1.341 - return _source.get_field(regs);
1.342 - else
1.343 - return 0;
1.344 -}
1.345 -
1.346 -void
1.347 -Source::set_source(Cpm_regs ®s, uint8_t source)
1.348 -{
1.349 - if (!_source.is_defined())
1.350 - return;
1.351 -
1.352 - _source.set_field(regs, source);
1.353 -}
1.354 -
1.355 -// Clock source frequencies.
1.356 -
1.357 -uint32_t
1.358 -Source::get_frequency(Cpm_regs ®s)
1.359 -{
1.360 - // Return the external clock frequency without any input clock.
1.361 -
1.362 - if (get_number() == 0)
1.363 - return regs.exclk_freq;
1.364 -
1.365 - // Clocks with one source yield that input frequency.
1.366 -
1.367 - else if (get_number() == 1)
1.368 - return clocks[get_input(0)]->get_frequency(regs);
1.369 -
1.370 - // With multiple sources, obtain the selected source for the clock.
1.371 -
1.372 - uint8_t source = get_source(regs);
1.373 - enum Clock_identifiers input = get_input(source);
1.374 -
1.375 - // Return the frequency of the source.
1.376 -
1.377 - if (input != Clock_undefined)
1.378 - return clocks[input]->get_frequency(regs);
1.379 - else
1.380 - return 0;
1.381 -}
1.382 -
1.383 -
1.384 -
1.385 -// Clock control.
1.386 -
1.387 -int
1.388 -Clock_base::have_clock(Cpm_regs ®s)
1.389 -{
1.390 - (void) regs;
1.391 - return true;
1.392 -}
1.393 -
1.394 -void
1.395 -Clock_base::start_clock(Cpm_regs ®s)
1.396 -{
1.397 - (void) regs;
1.398 -}
1.399 -
1.400 -void
1.401 -Clock_base::stop_clock(Cpm_regs ®s)
1.402 -{
1.403 - (void) regs;
1.404 -}
1.405 -
1.406 -// Default divider.
1.407 -
1.408 -uint32_t
1.409 -Clock_base::get_divider(Cpm_regs ®s)
1.410 -{
1.411 - (void) regs;
1.412 - return 1;
1.413 -}
1.414 -
1.415 -void
1.416 -Clock_base::set_divider(Cpm_regs ®s, uint32_t division)
1.417 -{
1.418 - (void) regs;
1.419 - (void) division;
1.420 -}
1.421 -
1.422 -// Clock sources.
1.423 -
1.424 -uint8_t
1.425 -Clock_base::get_source(Cpm_regs ®s)
1.426 -{
1.427 - return _source.get_source(regs);
1.428 -}
1.429 -
1.430 -void
1.431 -Clock_base::set_source(Cpm_regs ®s, uint8_t source)
1.432 -{
1.433 - _source.set_source(regs, source);
1.434 -}
1.435 -
1.436 -// Clock source frequencies.
1.437 -
1.438 -uint32_t
1.439 -Clock_base::get_source_frequency(Cpm_regs ®s)
1.440 -{
1.441 - return _source.get_frequency(regs);
1.442 -}
1.443 -
1.444 -// Output clock frequencies.
1.445 -
1.446 -uint32_t
1.447 -Clock_base::get_frequency(Cpm_regs ®s)
1.448 -{
1.449 - return get_source_frequency(regs) / get_divider(regs);
1.450 -}
1.451 -
1.452 -
1.453 -
1.454 -// PLL-specific control.
1.455 -
1.456 -int
1.457 -Pll::have_pll(Cpm_regs ®s)
1.458 -{
1.459 - return _stable.get_field(regs);
1.460 -}
1.461 -
1.462 -int
1.463 -Pll::pll_enabled(Cpm_regs ®s)
1.464 -{
1.465 - return _enable.get_field(regs);
1.466 -}
1.467 -
1.468 -int
1.469 -Pll::pll_bypassed(Cpm_regs ®s)
1.470 -{
1.471 - return _bypass.get_field(regs);
1.472 -}
1.473 -
1.474 -// Clock control.
1.475 -
1.476 -int
1.477 -Pll::have_clock(Cpm_regs ®s)
1.478 -{
1.479 - return have_pll(regs) && pll_enabled(regs);
1.480 -}
1.481 -
1.482 -void
1.483 -Pll::start_clock(Cpm_regs ®s)
1.484 -{
1.485 - _enable.set_field(regs, 1);
1.486 - while (!have_pll(regs));
1.487 -}
1.488 -
1.489 -void
1.490 -Pll::stop_clock(Cpm_regs ®s)
1.491 -{
1.492 - _enable.set_field(regs, 0);
1.493 - while (have_pll(regs));
1.494 -}
1.495 -
1.496 -// Feedback (13-bit) multiplier.
1.497 -
1.498 -uint16_t
1.499 -Pll::get_multiplier(Cpm_regs ®s)
1.500 -{
1.501 - return _multiplier.get_field(regs) + 1;
1.502 -}
1.503 -
1.504 -void
1.505 -Pll::set_multiplier(Cpm_regs ®s, uint16_t multiplier)
1.506 -{
1.507 - _multiplier.set_field(regs, multiplier - 1);
1.508 -}
1.509 -
1.510 -// Input (6-bit) divider.
1.511 -
1.512 -uint8_t
1.513 -Pll::get_input_division(Cpm_regs ®s)
1.514 -{
1.515 - return _input_division.get_field(regs) + 1;
1.516 -}
1.517 -
1.518 -void
1.519 -Pll::set_input_division(Cpm_regs ®s, uint8_t divider)
1.520 -{
1.521 - _input_division.set_field(regs, divider - 1);
1.522 -}
1.523 -
1.524 -// Output (dual 3-bit) dividers.
1.525 -
1.526 -uint8_t
1.527 -Pll::get_output_division(Cpm_regs ®s)
1.528 -{
1.529 - uint8_t d0 = _output_division0.get_field(regs);
1.530 - uint8_t d1 = _output_division1.get_field(regs);
1.531 -
1.532 - return d0 * d1;
1.533 -}
1.534 -
1.535 -void
1.536 -Pll::set_output_division(Cpm_regs ®s, uint8_t divider)
1.537 -{
1.538 - // Assert 1 as a minimum.
1.539 - // Divider 0 must be less than or equal to divider 1.
1.540 -
1.541 - uint8_t d0 = (uint8_t) floor(sqrt(divider ? divider : 1));
1.542 - uint8_t d1 = divider / d0;
1.543 -
1.544 - _output_division0.set_field(regs, d0);
1.545 - _output_division1.set_field(regs, d1);
1.546 -}
1.547 -
1.548 -uint32_t
1.549 -Pll::get_frequency(Cpm_regs ®s)
1.550 -{
1.551 - // Test for PLL enable and not PLL bypass.
1.552 -
1.553 - if (pll_enabled(regs))
1.554 - {
1.555 - if (!pll_bypassed(regs))
1.556 - return (get_source_frequency(regs) * get_multiplier(regs)) /
1.557 - (get_input_division(regs) * get_output_division(regs));
1.558 - else
1.559 - return get_source_frequency(regs);
1.560 - }
1.561 - else
1.562 - return 0;
1.563 -}
1.564 -
1.565 -void
1.566 -Pll::set_pll_parameters(Cpm_regs ®s, uint16_t multiplier, uint8_t in_divider, uint8_t out_divider)
1.567 -{
1.568 - set_multiplier(regs, multiplier);
1.569 - set_input_division(regs, in_divider);
1.570 - set_output_division(regs, out_divider);
1.571 -
1.572 - if (pll_enabled(regs) && !pll_bypassed(regs))
1.573 - while (!have_pll(regs));
1.574 -}
1.575 -
1.576 -
1.577 -
1.578 -// Clock control.
1.579 -
1.580 -void
1.581 -Clock::change_disable(Cpm_regs ®s)
1.582 -{
1.583 - if (_change_enable.is_defined())
1.584 - _change_enable.set_field(regs, 0);
1.585 -}
1.586 -
1.587 -void
1.588 -Clock::change_enable(Cpm_regs ®s)
1.589 -{
1.590 - if (_change_enable.is_defined())
1.591 - _change_enable.set_field(regs, 1);
1.592 -}
1.593 -
1.594 -int
1.595 -Clock::have_clock(Cpm_regs ®s)
1.596 -{
1.597 - if (_gate.is_defined())
1.598 - return !_gate.get_field(regs);
1.599 - else
1.600 - return true;
1.601 -}
1.602 -
1.603 -void
1.604 -Clock::start_clock(Cpm_regs ®s)
1.605 -{
1.606 - if (_gate.is_defined())
1.607 - _gate.set_field(regs, 0);
1.608 -}
1.609 -
1.610 -void
1.611 -Clock::stop_clock(Cpm_regs ®s)
1.612 -{
1.613 - if (_gate.is_defined())
1.614 - _gate.set_field(regs, 1);
1.615 -}
1.616 -
1.617 -void
1.618 -Clock::wait_busy(Cpm_regs ®s)
1.619 -{
1.620 - if (_busy.is_defined())
1.621 - while (_busy.get_field(regs));
1.622 -}
1.623 -
1.624 -
1.625 -
1.626 -// Clock dividers.
1.627 -
1.628 -uint32_t
1.629 -Clock::get_divider(Cpm_regs ®s)
1.630 -{
1.631 - if (_divider.is_defined())
1.632 - return _divider.get_field(regs) + 1;
1.633 - else
1.634 - return 1;
1.635 -}
1.636 -
1.637 -void
1.638 -Clock::set_divider(Cpm_regs ®s, uint32_t division)
1.639 -{
1.640 - if (!_divider.is_defined())
1.641 - return;
1.642 -
1.643 - change_enable(regs);
1.644 - _divider.set_field(regs, division - 1);
1.645 - wait_busy(regs);
1.646 - change_disable(regs);
1.647 -}
1.648 -
1.649 -void
1.650 -Clock::set_source(Cpm_regs ®s, uint8_t source)
1.651 -{
1.652 - change_enable(regs);
1.653 - Clock_base::set_source(regs, source);
1.654 - wait_busy(regs);
1.655 - change_disable(regs);
1.656 -}
1.657 -
1.658 -
1.659 -
1.660 // If implemented as a Hw::Device, various properties would be
1.661 // initialised in the constructor and obtained from the device tree
1.662 // definitions.
1.663
1.664 Cpm_x1600_chip::Cpm_x1600_chip(l4_addr_t addr, uint32_t exclk_freq)
1.665 -: _cpm_regs(addr, exclk_freq)
1.666 +: _cpm_regs(addr, clocks, exclk_freq)
1.667 {
1.668 // add_cid("cpm");
1.669 // add_cid("cpm-x1600");