Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions sw/device/lib/hal/clkmgr.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,57 @@
#include "hal/clkmgr.h"
#include "hal/mmio.h"
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

static uint32_t clkmgr_read(clkmgr_t clkmgr, uintptr_t reg)
{
return DEV_READ(clkmgr + reg);
}

static void clkmgr_write(clkmgr_t clkmgr, uintptr_t reg, uint32_t value)
{
DEV_WRITE(clkmgr + reg, value);
}

static uint32_t clkmgr_bit(size_t clock)
{
return 1u << clock;
}

Comment on lines +11 to +25
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These don't look like clock manager specific functions. Do they already exist elsewhere in the repo?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did not find another helper for this, only the DEV_READ and DEV_WRITE macros. I added these local helpers to avoid repeating the same code in this file. I can also remove them and use DEV_READ/DEV_WRITE directly if you prefer.

bool clkmgr_gateable_clock_get_enabled(clkmgr_t clkmgr, size_t clock)
{
return (clkmgr_read(clkmgr, CLKMGR_CLK_ENABLES_REG) & clkmgr_bit(clock)) != 0;
}

void clkmgr_gateable_clock_set_enabled(clkmgr_t clkmgr, size_t clock, bool enabled)
{
uint32_t reg = clkmgr_read(clkmgr, CLKMGR_CLK_ENABLES_REG);
if (enabled) {
reg |= clkmgr_bit(clock);
} else {
reg &= ~clkmgr_bit(clock);
}
clkmgr_write(clkmgr, CLKMGR_CLK_ENABLES_REG, reg);
}

bool clkmgr_hintable_clock_get_hint(clkmgr_t clkmgr, size_t clock)
{
return (clkmgr_read(clkmgr, CLKMGR_CLK_HINTS_REG) & clkmgr_bit(clock)) != 0;
}

void clkmgr_hintable_clock_set_hint(clkmgr_t clkmgr, size_t clock, bool enabled)
{
uint32_t reg = clkmgr_read(clkmgr, CLKMGR_CLK_HINTS_REG);
if (enabled) {
reg |= clkmgr_bit(clock);
} else {
reg &= ~clkmgr_bit(clock);
}
clkmgr_write(clkmgr, CLKMGR_CLK_HINTS_REG, reg);
}

bool clkmgr_hintable_clock_get_enabled(clkmgr_t clkmgr, size_t clock)
{
return (clkmgr_read(clkmgr, CLKMGR_CLK_HINTS_STATUS_REG) & clkmgr_bit(clock)) != 0;
}
20 changes: 17 additions & 3 deletions sw/device/lib/hal/clkmgr.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,26 @@
#pragma once

#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

#define CLKMGR_ALERT_TEST_REG (0x00)
#define CLKMGR_CLK_ENABLES_REG (0x18)
#define CLKMGR_CLK_ENABLES_ALL (1)
#define CLKMGR_ALERT_TEST_REG (0x00)
#define CLKMGR_JITTER_REGWEN_REG (0x10)
#define CLKMGR_JITTER_ENABLE_REG (0x14)
#define CLKMGR_CLK_ENABLES_REG (0x18)
#define CLKMGR_CLK_HINTS_REG (0x1c)
#define CLKMGR_CLK_HINTS_STATUS_REG (0x20)

#define CLKMGR_GATEABLE_CLOCK_IO_PERI (0u)
#define CLKMGR_HINTABLE_CLOCK_MAIN (0u)

typedef void *clkmgr_t;

#define CLKMGR_FROM_BASE_ADDR(addr) ((clkmgr_t)(addr))

bool clkmgr_gateable_clock_get_enabled(clkmgr_t clkmgr, size_t clock);
void clkmgr_gateable_clock_set_enabled(clkmgr_t clkmgr, size_t clock, bool enabled);

bool clkmgr_hintable_clock_get_hint(clkmgr_t clkmgr, size_t clock);
void clkmgr_hintable_clock_set_hint(clkmgr_t clkmgr, size_t clock, bool enabled);
bool clkmgr_hintable_clock_get_enabled(clkmgr_t clkmgr, size_t clock);
15 changes: 12 additions & 3 deletions sw/device/lib/hal/rstmgr.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,28 @@

#include "hal/rstmgr.h"
#include "hal/mmio.h"
#include "hal/mocha.h"
#include <stdint.h>

uint32_t rstmgr_reset_reason_get(rstmgr_t rstmgr)
{
return DEV_READ(rstmgr + RSTMGR_RESET_INFO_REG);
}

void rstmgr_reset_reason_clear(rstmgr_t rstmgr, uint32_t reason)
{
DEV_WRITE(rstmgr + RSTMGR_RESET_INFO_REG, reason);
}

void rstmgr_software_reset_request(rstmgr_t rstmgr)
{
DEV_WRITE(rstmgr + RSTMGR_RESET_REQ_REG, RSTMGR_RESET_REQ_TRUE);
}

bool rstmgr_software_reset_info_get(rstmgr_t rstmgr)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can now remove this function. I think it was only used in the software_reset test.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. The test now reads and clears the reset reason directly, so this function is not needed anymore. I will remove it from the HAL source and header.

{
if (DEV_READ(rstmgr + RSTMGR_RESET_INFO_REG) & RSTMGR_RESET_INFO_SW_RESET) {
if (rstmgr_reset_reason_get(rstmgr) & RSTMGR_RESET_INFO_SW_RESET) {
// Clear the info bit before returning.
DEV_WRITE(rstmgr + RSTMGR_RESET_INFO_REG, RSTMGR_RESET_INFO_SW_RESET);
rstmgr_reset_reason_clear(rstmgr, RSTMGR_RESET_INFO_SW_RESET);
return true;
}
return false;
Expand Down
5 changes: 5 additions & 0 deletions sw/device/lib/hal/rstmgr.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,16 @@
#define RSTMGR_RESET_REQ_REG (0x4)
#define RSTMGR_RESET_REQ_TRUE (kMultiBitBool4True)
#define RSTMGR_RESET_INFO_REG (0x8)
#define RSTMGR_RESET_INFO_POR (0x1)
#define RSTMGR_RESET_INFO_LOW_PWR (0x2)
#define RSTMGR_RESET_INFO_SW_RESET (0x4)

typedef void *rstmgr_t;

#define RSTMGR_FROM_BASE_ADDR(addr) ((rstmgr_t)(addr))

uint32_t rstmgr_reset_reason_get(rstmgr_t rstmgr);
void rstmgr_reset_reason_clear(rstmgr_t rstmgr, uint32_t reason);

void rstmgr_software_reset_request(rstmgr_t rstmgr);
bool rstmgr_software_reset_info_get(rstmgr_t rstmgr);
1 change: 1 addition & 0 deletions sw/device/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ mocha_add_test(NAME test_framework_test SOURCES test_framework/smoketest.c LIBRA
mocha_add_test(NAME test_framework_exception_test SOURCES test_framework/exception.c LIBRARIES ${LIBS})
mocha_add_test(NAME axi_sram_smoketest SOURCES axi_sram/smoketest.c LIBRARIES ${LIBS} FPGA)
mocha_add_test(NAME axi_sram_tag_test SOURCES axi_sram/tag_test.c LIBRARIES ${LIBS} FPGA)
mocha_add_test(NAME clkmgr_smoketest SOURCES clkmgr/clkmgr_smoke_test.c LIBRARIES ${LIBS})
mocha_add_test(NAME gpio_reg_access_test SOURCES gpio/reg_access_test.c LIBRARIES ${LIBS} FPGA)
mocha_add_test(NAME i2c_smoketest SOURCES i2c/smoketest.c LIBRARIES ${LIBS} FPGA)
mocha_add_test(NAME mailbox_smoketest SOURCES mailbox/smoketest.c LIBRARIES ${LIBS} FPGA)
Expand Down
46 changes: 46 additions & 0 deletions sw/device/tests/clkmgr/clkmgr_smoke_test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright lowRISC contributors (COSMIC project).
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

#include "hal/clkmgr.h"
#include "hal/mocha.h"
#include <stdbool.h>
#include <stdint.h>

static bool test_gateable_clock(clkmgr_t clkmgr)
{
bool initial = clkmgr_gateable_clock_get_enabled(clkmgr, CLKMGR_GATEABLE_CLOCK_IO_PERI);
bool toggled = !initial;

clkmgr_gateable_clock_set_enabled(clkmgr, CLKMGR_GATEABLE_CLOCK_IO_PERI, toggled);
if (clkmgr_gateable_clock_get_enabled(clkmgr, CLKMGR_GATEABLE_CLOCK_IO_PERI) != toggled) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any way that we can confirm that the peripherals are actually stopped? I'm not sure whether reading a register will cause a bus error or just hang the design.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this software smoke test can safely check that. If we read from a peripheral after stopping its clock, it may hang the design. This test only checks that the clkmgr registers can be written and read back correctly. I think checking that the clock really stops should be done in DV, where we can observe the clock signals directly.

return false;
}

clkmgr_gateable_clock_set_enabled(clkmgr, CLKMGR_GATEABLE_CLOCK_IO_PERI, initial);
return clkmgr_gateable_clock_get_enabled(clkmgr, CLKMGR_GATEABLE_CLOCK_IO_PERI) == initial;
}

static bool test_hintable_clock(clkmgr_t clkmgr)
{
bool initial = clkmgr_hintable_clock_get_hint(clkmgr, CLKMGR_HINTABLE_CLOCK_MAIN);
bool toggled = !initial;

clkmgr_hintable_clock_set_hint(clkmgr, CLKMGR_HINTABLE_CLOCK_MAIN, toggled);
if (clkmgr_hintable_clock_get_hint(clkmgr, CLKMGR_HINTABLE_CLOCK_MAIN) != toggled) {
return false;
}

if (toggled && !clkmgr_hintable_clock_get_enabled(clkmgr, CLKMGR_HINTABLE_CLOCK_MAIN)) {
return false;
}

clkmgr_hintable_clock_set_hint(clkmgr, CLKMGR_HINTABLE_CLOCK_MAIN, initial);
return clkmgr_hintable_clock_get_hint(clkmgr, CLKMGR_HINTABLE_CLOCK_MAIN) == initial;
}

bool test_main()
{
clkmgr_t clkmgr = mocha_system_clkmgr();
return test_gateable_clock(clkmgr) && test_hintable_clock(clkmgr);
}
18 changes: 12 additions & 6 deletions sw/device/tests/rstmgr/software_reset.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,21 @@
bool test_main()
{
rstmgr_t rstmgr = mocha_system_rstmgr();
uint32_t reason = rstmgr_reset_reason_get(rstmgr);

if (rstmgr_software_reset_info_get(rstmgr)) {
return true;
if (reason & RSTMGR_RESET_INFO_POR) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, this is a good change!

rstmgr_reset_reason_clear(rstmgr, RSTMGR_RESET_INFO_POR);
rstmgr_software_reset_request(rstmgr);

// Must wait here for reset to happen.
while (1) {
}
}
// Request a reset of the system.
rstmgr_software_reset_request(rstmgr);

// Must wait here for reset to happen.
while (1) {
if (reason & RSTMGR_RESET_INFO_SW_RESET) {
rstmgr_reset_reason_clear(rstmgr, RSTMGR_RESET_INFO_SW_RESET);
return true;
}

return false;
}