stm32l4x5_rcc.c (d6b55a0fe9920b46d380f50d7da48ff43de21324) | stm32l4x5_rcc.c (ec7d83acbd1182d47df742745b43e6b16a3a4977) |
---|---|
1/* 2 * STM32L4X5 RCC (Reset and clock control) 3 * 4 * Copyright (c) 2023 Arnaud Minier <arnaud.minier@telecom-paris.fr> 5 * Copyright (c) 2023 Inès Varhol <ines.varhol@telecom-paris.fr> 6 * 7 * SPDX-License-Identifier: GPL-2.0-or-later 8 * --- 22 unchanged lines hidden (view full) --- 31#include "trace.h" 32 33#define HSE_DEFAULT_FRQ 48000000ULL 34#define HSI_FRQ 16000000ULL 35#define MSI_DEFAULT_FRQ 4000000ULL 36#define LSE_FRQ 32768ULL 37#define LSI_FRQ 32000ULL 38 | 1/* 2 * STM32L4X5 RCC (Reset and clock control) 3 * 4 * Copyright (c) 2023 Arnaud Minier <arnaud.minier@telecom-paris.fr> 5 * Copyright (c) 2023 Inès Varhol <ines.varhol@telecom-paris.fr> 6 * 7 * SPDX-License-Identifier: GPL-2.0-or-later 8 * --- 22 unchanged lines hidden (view full) --- 31#include "trace.h" 32 33#define HSE_DEFAULT_FRQ 48000000ULL 34#define HSI_FRQ 16000000ULL 35#define MSI_DEFAULT_FRQ 4000000ULL 36#define LSE_FRQ 32768ULL 37#define LSI_FRQ 32000ULL 38 |
39static void clock_mux_update(RccClockMuxState *mux) 40{ 41 uint64_t src_freq; 42 Clock *current_source = mux->srcs[mux->src]; 43 uint32_t freq_multiplier = 0; 44 /* 45 * To avoid rounding errors, we use the clock period instead of the 46 * frequency. 47 * This means that the multiplier of the mux becomes the divider of 48 * the clock and the divider of the mux becomes the multiplier of the 49 * clock. 50 */ 51 if (mux->enabled && mux->divider) { 52 freq_multiplier = mux->divider; 53 } 54 55 clock_set_mul_div(mux->out, freq_multiplier, mux->multiplier); 56 clock_update(mux->out, clock_get(current_source)); 57 58 src_freq = clock_get_hz(current_source); 59 /* TODO: can we simply detect if the config changed so that we reduce log spam ? */ 60 trace_stm32l4x5_rcc_mux_update(mux->id, mux->src, src_freq, 61 mux->multiplier, mux->divider); 62} 63 64static void clock_mux_src_update(void *opaque, ClockEvent event) 65{ 66 RccClockMuxState **backref = opaque; 67 RccClockMuxState *s = *backref; 68 /* 69 * The backref value is equal to: 70 * s->backref + (sizeof(RccClockMuxState *) * update_src). 71 * By subtracting we can get back the index of the updated clock. 72 */ 73 const uint32_t update_src = backref - s->backref; 74 /* Only update if the clock that was updated is the current source */ 75 if (update_src == s->src) { 76 clock_mux_update(s); 77 } 78} 79 80static void clock_mux_init(Object *obj) 81{ 82 RccClockMuxState *s = RCC_CLOCK_MUX(obj); 83 size_t i; 84 85 for (i = 0; i < RCC_NUM_CLOCK_MUX_SRC; i++) { 86 char *name = g_strdup_printf("srcs[%zu]", i); 87 s->backref[i] = s; 88 s->srcs[i] = qdev_init_clock_in(DEVICE(s), name, 89 clock_mux_src_update, 90 &s->backref[i], 91 ClockUpdate); 92 g_free(name); 93 } 94 95 s->out = qdev_init_clock_out(DEVICE(s), "out"); 96} 97 98static void clock_mux_reset_hold(Object *obj) 99{ } 100 101static const VMStateDescription clock_mux_vmstate = { 102 .name = TYPE_RCC_CLOCK_MUX, 103 .version_id = 1, 104 .minimum_version_id = 1, 105 .fields = (VMStateField[]) { 106 VMSTATE_UINT32(id, RccClockMuxState), 107 VMSTATE_ARRAY_CLOCK(srcs, RccClockMuxState, 108 RCC_NUM_CLOCK_MUX_SRC), 109 VMSTATE_BOOL(enabled, RccClockMuxState), 110 VMSTATE_UINT32(src, RccClockMuxState), 111 VMSTATE_UINT32(multiplier, RccClockMuxState), 112 VMSTATE_UINT32(divider, RccClockMuxState), 113 VMSTATE_END_OF_LIST() 114 } 115}; 116 117static void clock_mux_class_init(ObjectClass *klass, void *data) 118{ 119 DeviceClass *dc = DEVICE_CLASS(klass); 120 ResettableClass *rc = RESETTABLE_CLASS(klass); 121 122 rc->phases.hold = clock_mux_reset_hold; 123 dc->vmsd = &clock_mux_vmstate; 124} 125 126static void clock_mux_set_enable(RccClockMuxState *mux, bool enabled) 127{ 128 if (mux->enabled == enabled) { 129 return; 130 } 131 132 if (enabled) { 133 trace_stm32l4x5_rcc_mux_enable(mux->id); 134 } else { 135 trace_stm32l4x5_rcc_mux_disable(mux->id); 136 } 137 138 mux->enabled = enabled; 139 clock_mux_update(mux); 140} 141 142static void clock_mux_set_factor(RccClockMuxState *mux, 143 uint32_t multiplier, uint32_t divider) 144{ 145 if (mux->multiplier == multiplier && mux->divider == divider) { 146 return; 147 } 148 trace_stm32l4x5_rcc_mux_set_factor(mux->id, 149 mux->multiplier, multiplier, mux->divider, divider); 150 151 mux->multiplier = multiplier; 152 mux->divider = divider; 153 clock_mux_update(mux); 154} 155 156static void clock_mux_set_source(RccClockMuxState *mux, RccClockMuxSource src) 157{ 158 if (mux->src == src) { 159 return; 160 } 161 162 trace_stm32l4x5_rcc_mux_set_src(mux->id, mux->src, src); 163 mux->src = src; 164 clock_mux_update(mux); 165} 166 |
|
39static void rcc_update_irq(Stm32l4x5RccState *s) 40{ 41 if (s->cifr & CIFR_IRQ_MASK) { 42 qemu_irq_raise(s->irq); 43 } else { 44 qemu_irq_lower(s->irq); 45 } 46} --- 283 unchanged lines hidden (view full) --- 330 QDEV_CLOCK_IN(Stm32l4x5RccState, sai2_extclk, NULL, 0), 331 QDEV_CLOCK_END 332}; 333 334 335static void stm32l4x5_rcc_init(Object *obj) 336{ 337 Stm32l4x5RccState *s = STM32L4X5_RCC(obj); | 167static void rcc_update_irq(Stm32l4x5RccState *s) 168{ 169 if (s->cifr & CIFR_IRQ_MASK) { 170 qemu_irq_raise(s->irq); 171 } else { 172 qemu_irq_lower(s->irq); 173 } 174} --- 283 unchanged lines hidden (view full) --- 458 QDEV_CLOCK_IN(Stm32l4x5RccState, sai2_extclk, NULL, 0), 459 QDEV_CLOCK_END 460}; 461 462 463static void stm32l4x5_rcc_init(Object *obj) 464{ 465 Stm32l4x5RccState *s = STM32L4X5_RCC(obj); |
466 size_t i; |
|
338 339 sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq); 340 341 memory_region_init_io(&s->mmio, obj, &stm32l4x5_rcc_ops, s, 342 TYPE_STM32L4X5_RCC, 0x400); 343 sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); 344 345 qdev_init_clocks(DEVICE(s), stm32l4x5_rcc_clocks); 346 | 467 468 sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq); 469 470 memory_region_init_io(&s->mmio, obj, &stm32l4x5_rcc_ops, s, 471 TYPE_STM32L4X5_RCC, 0x400); 472 sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); 473 474 qdev_init_clocks(DEVICE(s), stm32l4x5_rcc_clocks); 475 |
476 for (i = 0; i < RCC_NUM_CLOCK_MUX; i++) { 477 478 object_initialize_child(obj, "clock[*]", 479 &s->clock_muxes[i], 480 TYPE_RCC_CLOCK_MUX); 481 482 } 483 |
|
347 s->gnd = clock_new(obj, "gnd"); 348} 349 350static const VMStateDescription vmstate_stm32l4x5_rcc = { 351 .name = TYPE_STM32L4X5_RCC, 352 .version_id = 1, 353 .minimum_version_id = 1, 354 .fields = (VMStateField[]) { --- 36 unchanged lines hidden (view full) --- 391 VMSTATE_END_OF_LIST() 392 } 393}; 394 395 396static void stm32l4x5_rcc_realize(DeviceState *dev, Error **errp) 397{ 398 Stm32l4x5RccState *s = STM32L4X5_RCC(dev); | 484 s->gnd = clock_new(obj, "gnd"); 485} 486 487static const VMStateDescription vmstate_stm32l4x5_rcc = { 488 .name = TYPE_STM32L4X5_RCC, 489 .version_id = 1, 490 .minimum_version_id = 1, 491 .fields = (VMStateField[]) { --- 36 unchanged lines hidden (view full) --- 528 VMSTATE_END_OF_LIST() 529 } 530}; 531 532 533static void stm32l4x5_rcc_realize(DeviceState *dev, Error **errp) 534{ 535 Stm32l4x5RccState *s = STM32L4X5_RCC(dev); |
536 size_t i; |
|
399 400 if (s->hse_frequency < 4000000ULL || 401 s->hse_frequency > 48000000ULL) { 402 error_setg(errp, 403 "HSE frequency is outside of the allowed [4-48]Mhz range: %" PRIx64 "", 404 s->hse_frequency); 405 return; 406 } 407 | 537 538 if (s->hse_frequency < 4000000ULL || 539 s->hse_frequency > 48000000ULL) { 540 error_setg(errp, 541 "HSE frequency is outside of the allowed [4-48]Mhz range: %" PRIx64 "", 542 s->hse_frequency); 543 return; 544 } 545 |
546 for (i = 0; i < RCC_NUM_CLOCK_MUX; i++) { 547 RccClockMuxState *clock_mux = &s->clock_muxes[i]; 548 549 if (!qdev_realize(DEVICE(clock_mux), NULL, errp)) { 550 return; 551 } 552 } 553 |
|
408 clock_update_hz(s->msi_rc, MSI_DEFAULT_FRQ); 409 clock_update_hz(s->sai1_extclk, s->sai1_extclk_frequency); 410 clock_update_hz(s->sai2_extclk, s->sai2_extclk_frequency); 411 clock_update(s->gnd, 0); | 554 clock_update_hz(s->msi_rc, MSI_DEFAULT_FRQ); 555 clock_update_hz(s->sai1_extclk, s->sai1_extclk_frequency); 556 clock_update_hz(s->sai2_extclk, s->sai2_extclk_frequency); 557 clock_update(s->gnd, 0); |
558 559 /* 560 * Dummy values to make compilation pass. 561 * Removed in later commits. 562 */ 563 clock_mux_set_source(&s->clock_muxes[0], RCC_CLOCK_MUX_SRC_GND); 564 clock_mux_set_enable(&s->clock_muxes[0], true); 565 clock_mux_set_factor(&s->clock_muxes[0], 1, 1); |
|
412} 413 414static Property stm32l4x5_rcc_properties[] = { 415 DEFINE_PROP_UINT64("hse_frequency", Stm32l4x5RccState, 416 hse_frequency, HSE_DEFAULT_FRQ), 417 DEFINE_PROP_UINT64("sai1_extclk_frequency", Stm32l4x5RccState, 418 sai1_extclk_frequency, 0), 419 DEFINE_PROP_UINT64("sai2_extclk_frequency", Stm32l4x5RccState, --- 15 unchanged lines hidden (view full) --- 435 436static const TypeInfo stm32l4x5_rcc_types[] = { 437 { 438 .name = TYPE_STM32L4X5_RCC, 439 .parent = TYPE_SYS_BUS_DEVICE, 440 .instance_size = sizeof(Stm32l4x5RccState), 441 .instance_init = stm32l4x5_rcc_init, 442 .class_init = stm32l4x5_rcc_class_init, | 566} 567 568static Property stm32l4x5_rcc_properties[] = { 569 DEFINE_PROP_UINT64("hse_frequency", Stm32l4x5RccState, 570 hse_frequency, HSE_DEFAULT_FRQ), 571 DEFINE_PROP_UINT64("sai1_extclk_frequency", Stm32l4x5RccState, 572 sai1_extclk_frequency, 0), 573 DEFINE_PROP_UINT64("sai2_extclk_frequency", Stm32l4x5RccState, --- 15 unchanged lines hidden (view full) --- 589 590static const TypeInfo stm32l4x5_rcc_types[] = { 591 { 592 .name = TYPE_STM32L4X5_RCC, 593 .parent = TYPE_SYS_BUS_DEVICE, 594 .instance_size = sizeof(Stm32l4x5RccState), 595 .instance_init = stm32l4x5_rcc_init, 596 .class_init = stm32l4x5_rcc_class_init, |
597 }, { 598 .name = TYPE_RCC_CLOCK_MUX, 599 .parent = TYPE_DEVICE, 600 .instance_size = sizeof(RccClockMuxState), 601 .instance_init = clock_mux_init, 602 .class_init = clock_mux_class_init, |
|
443 } 444}; 445 446DEFINE_TYPES(stm32l4x5_rcc_types) | 603 } 604}; 605 606DEFINE_TYPES(stm32l4x5_rcc_types) |