Skip to content
Open
Show file tree
Hide file tree
Changes from 3 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
2 changes: 1 addition & 1 deletion sw/device/lib/hal/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0

set(SRCS clkmgr.c gpio.c i2c.c mailbox.c mocha.c plic.c rom_ctrl.c rstmgr.c spi_device.c spi_host.c timer.c uart.c)
set(SRCS clkmgr.c gpio.c i2c.c mailbox.c mocha.c plic.c pwrmgr.c rom_ctrl.c rstmgr.c spi_device.c spi_host.c timer.c uart.c)

mocha_add_library(NAME hal LIBRARIES SOURCES ${SRCS})
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);
10 changes: 10 additions & 0 deletions sw/device/lib/hal/mocha.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ static const uintptr_t dv_test_status_base = 0x20020000ul;
static const uintptr_t gpio_base = 0x40000000ul;
static const uintptr_t clkmgr_base = 0x40020000ul;
static const uintptr_t rstmgr_base = 0x40030000ul;
static const uintptr_t pwrmgr_base = 0x40040000ul;
static const uintptr_t rom_ctrl_base = 0x40050000ul;
static const uintptr_t uart_base = 0x41000000ul;
static const uintptr_t i2c_base = 0x42000000ul;
Expand Down Expand Up @@ -90,6 +91,15 @@ rstmgr_t mocha_system_rstmgr(void)
#endif /* defined(__riscv_zcherihybrid) */
}

pwrmgr_t mocha_system_pwrmgr(void)
{
#if defined(__riscv_zcherihybrid)
return (pwrmgr_t)create_mmio_capability(pwrmgr_base, 0x80u);
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 this length can be 0x44

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.

Agreed. The highest register used here is WAKE_INFO at 0x3c, so 0x44 is enough. I will change it from 0x80 to 0x44.

#else /* !defined(__riscv_zcherihybrid) */
return (pwrmgr_t)pwrmgr_base;
#endif /* defined(__riscv_zcherihybrid) */
}

rom_ctrl_t mocha_system_rom_ctrl(void)
{
#if defined(__riscv_zcherihybrid)
Expand Down
2 changes: 2 additions & 0 deletions sw/device/lib/hal/mocha.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "hal/i2c.h"
#include "hal/mailbox.h"
#include "hal/plic.h"
#include "hal/pwrmgr.h"
#include "hal/rom_ctrl.h"
#include "hal/rstmgr.h"
#include "hal/spi_device.h"
Expand All @@ -36,6 +37,7 @@ mailbox_t mocha_system_mailbox(void);
gpio_t mocha_system_gpio(void);
clkmgr_t mocha_system_clkmgr(void);
rstmgr_t mocha_system_rstmgr(void);
pwrmgr_t mocha_system_pwrmgr(void);
rom_ctrl_t mocha_system_rom_ctrl(void);
uart_t mocha_system_uart(void);
i2c_t mocha_system_i2c(void);
Expand Down
69 changes: 69 additions & 0 deletions sw/device/lib/hal/pwrmgr.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// 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/pwrmgr.h"
#include "hal/mmio.h"
#include <stdint.h>

static uint32_t pwrmgr_read(pwrmgr_t pwrmgr, uintptr_t reg)
{
return DEV_READ(pwrmgr + reg);
}

static void pwrmgr_write(pwrmgr_t pwrmgr, uintptr_t reg, uint32_t value)
{
DEV_WRITE(pwrmgr + reg, value);
}

uint32_t pwrmgr_control_get(pwrmgr_t pwrmgr)
{
return pwrmgr_read(pwrmgr, PWRMGR_CONTROL_REG);
}
Comment on lines +9 to +22
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.

Replicated from clock manager.

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.

Yes, I copied the same style from clkmgr. I can keep both files like this, or I can remove these helpers and use DEV_READ/DEV_WRITE directly in both files.


void pwrmgr_control_set(pwrmgr_t pwrmgr, uint32_t value)
{
pwrmgr_write(pwrmgr, PWRMGR_CONTROL_REG, value & PWRMGR_CONTROL_MASK);
}

void pwrmgr_cfg_sync(pwrmgr_t pwrmgr)
{
pwrmgr_write(pwrmgr, PWRMGR_CFG_CDC_SYNC_REG, 1u);
while ((pwrmgr_read(pwrmgr, PWRMGR_CFG_CDC_SYNC_REG) & 1u) != 0u) {
}
}

uint32_t pwrmgr_wakeup_enable_get(pwrmgr_t pwrmgr)
{
return pwrmgr_read(pwrmgr, PWRMGR_WAKEUP_EN_REG);
}

void pwrmgr_wakeup_enable_set(pwrmgr_t pwrmgr, uint32_t value)
{
pwrmgr_write(pwrmgr, PWRMGR_WAKEUP_EN_REG, value);
}

uint32_t pwrmgr_wakeup_status_get(pwrmgr_t pwrmgr)
{
return pwrmgr_read(pwrmgr, PWRMGR_WAKE_STATUS_REG);
}

uint32_t pwrmgr_reset_status_get(pwrmgr_t pwrmgr)
{
return pwrmgr_read(pwrmgr, PWRMGR_RESET_STATUS_REG);
}

uint32_t pwrmgr_escalate_reset_status_get(pwrmgr_t pwrmgr)
{
return pwrmgr_read(pwrmgr, PWRMGR_ESCALATE_RESET_STATUS_REG);
}

uint32_t pwrmgr_wake_info_get(pwrmgr_t pwrmgr)
{
return pwrmgr_read(pwrmgr, PWRMGR_WAKE_INFO_REG);
}

void pwrmgr_wake_info_clear(pwrmgr_t pwrmgr, uint32_t mask)
{
pwrmgr_write(pwrmgr, PWRMGR_WAKE_INFO_REG, mask);
}
50 changes: 50 additions & 0 deletions sw/device/lib/hal/pwrmgr.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright lowRISC contributors (COSMIC project).
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

// Power manager interface.

#pragma once

#include <stdint.h>

#define PWRMGR_CONTROL_REG (0x14)
#define PWRMGR_CFG_CDC_SYNC_REG (0x18)
#define PWRMGR_WAKEUP_EN_REG (0x20)
#define PWRMGR_WAKE_STATUS_REG (0x24)
#define PWRMGR_RESET_STATUS_REG (0x30)
#define PWRMGR_ESCALATE_RESET_STATUS_REG (0x34)
#define PWRMGR_WAKE_INFO_REG (0x3C)

#define PWRMGR_CONTROL_LOW_POWER_HINT_BIT (1u << 0)
#define PWRMGR_CONTROL_CORE_CLK_EN_BIT (1u << 4)
#define PWRMGR_CONTROL_IO_CLK_EN_BIT (1u << 5)
#define PWRMGR_CONTROL_MAIN_PD_N_BIT (1u << 6)
#define PWRMGR_CONTROL_MASK \
(PWRMGR_CONTROL_LOW_POWER_HINT_BIT | PWRMGR_CONTROL_CORE_CLK_EN_BIT | \
PWRMGR_CONTROL_IO_CLK_EN_BIT | PWRMGR_CONTROL_MAIN_PD_N_BIT)

#define PWRMGR_WAKEUP_EN_SOC_PROXY_EXT_WKUP_REQ_BIT (1u << 0)

#define PWRMGR_WAKE_INFO_REASONS_BIT (1u << 0)
#define PWRMGR_WAKE_INFO_FALL_THROUGH_BIT (1u << 1)
#define PWRMGR_WAKE_INFO_ABORT_BIT (1u << 2)

typedef void *pwrmgr_t;

#define PWRMGR_FROM_BASE_ADDR(addr) ((pwrmgr_t)(addr))

uint32_t pwrmgr_control_get(pwrmgr_t pwrmgr);
void pwrmgr_control_set(pwrmgr_t pwrmgr, uint32_t value);

void pwrmgr_cfg_sync(pwrmgr_t pwrmgr);

uint32_t pwrmgr_wakeup_enable_get(pwrmgr_t pwrmgr);
void pwrmgr_wakeup_enable_set(pwrmgr_t pwrmgr, uint32_t value);

uint32_t pwrmgr_wakeup_status_get(pwrmgr_t pwrmgr);
uint32_t pwrmgr_reset_status_get(pwrmgr_t pwrmgr);
uint32_t pwrmgr_escalate_reset_status_get(pwrmgr_t pwrmgr);

uint32_t pwrmgr_wake_info_get(pwrmgr_t pwrmgr);
void pwrmgr_wake_info_clear(pwrmgr_t pwrmgr, uint32_t mask);
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);
2 changes: 2 additions & 0 deletions sw/device/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ 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)
mocha_add_test(NAME plic_smoketest SOURCES plic/smoketest.c LIBRARIES ${LIBS} FPGA)
mocha_add_test(NAME pwrmgr_smoketest SOURCES pwrmgr/pwrmgr_smoke_test.c LIBRARIES ${LIBS})
mocha_add_test(NAME rom_ctrl_smoketest SOURCES rom_ctrl/smoketest.c LIBRARIES ${LIBS} FPGA)
# Cannot currently run this on FPGA because the boot ROM expects the test to be provided on the SPI again.
mocha_add_test(NAME rstmgr_software_reset SOURCES rstmgr/software_reset.c LIBRARIES ${LIBS})
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);
}
Loading
Loading