Files
test/drivers/source/scr/sdrv_scr.c
2025-11-07 20:19:23 +08:00

178 lines
4.4 KiB
C

/**
* @file sdrv_scr.c
* @brief Semidrive Status and Controller Register driver
*
* @copyright Copyright (c) 2022 Semidrive Semiconductor.
* All rights reserved.
*/
#include <debug.h>
#include <bits.h>
#include <irq.h>
#include <reg.h>
#include "sdrv_scr.h"
#define SCR_REG_OFF_TYPE_RW 0x1000
#define SCR_REG_OFF_TYPE_RO 0x1100
#define SCR_REG_OFF_TYPE_L16 0x1200
#define SCR_REG_OFF_TYPE_L31 0x1400
#define SCR_REG_OFF_TYPE_R16W16 0x1600
#define BITFIELD_POS_MSK 0x1Fu
static inline uint32_t _scr_reg_off(uint32_t type)
{
static const uint32_t reg_off[] = {
[TYPE_RW] = SCR_REG_OFF_TYPE_RW,
[TYPE_RO] = SCR_REG_OFF_TYPE_RO,
[TYPE_L16] = SCR_REG_OFF_TYPE_L16,
[TYPE_L31] = SCR_REG_OFF_TYPE_L31,
[TYPE_R16W16] = SCR_REG_OFF_TYPE_R16W16,
};
if (type <= TYPE_R16W16)
return reg_off[type];
return 0;
}
static inline uint32_t _scr_reg(const uint32_t base, const scr_signal_t *signal)
{
uint32_t reg_off =
_scr_reg_off(signal->type) + (signal->start_bit >> 5) * 4;
return base + reg_off;
}
static inline uint32_t _scr_read_reg(const uint32_t base,
const scr_signal_t *signal)
{
return readl(_scr_reg(base, signal));
}
static inline void _scr_write_reg(const uint32_t base,
const scr_signal_t *signal, uint32_t val)
{
writel(val, _scr_reg(base, signal));
}
uint32_t scr_get(const sdrv_scr_t *scr, const scr_signal_t *signal)
{
ASSERT(scr != NULL && signal != NULL);
uint32_t val = _scr_read_reg(scr->base, signal);
uint32_t start_bit = signal->start_bit & BITFIELD_POS_MSK;
return (val >> start_bit) & BIT_MASK(signal->width);
}
status_t scr_set(const sdrv_scr_t *scr, const scr_signal_t *signal,
uint32_t value)
{
ASSERT(scr != NULL && signal != NULL);
uint32_t start_bit;
uint32_t val;
irq_state_t state;
start_bit = signal->start_bit & BITFIELD_POS_MSK;
value &= BIT_MASK(signal->width);
if (signal->type == TYPE_L16 || signal->type == TYPE_L31) {
if (scr_is_locked(scr, signal))
return SDRV_SCR_LOCKED;
} else if (signal->type == TYPE_RO) {
return SDRV_SCR_CANNOT_WRITE;
} else if (signal->type == TYPE_R16W16) {
if (start_bit >= 16)
return SDRV_SCR_CANNOT_WRITE;
}
state = arch_irq_save();
val = _scr_read_reg(scr->base, signal);
val &= ~(BIT_MASK(signal->width) << start_bit);
val |= value << start_bit;
_scr_write_reg(scr->base, signal, val);
arch_irq_restore(state);
return SDRV_STATUS_OK;
}
status_t scr_lock(const sdrv_scr_t *scr, const scr_signal_t *signal)
{
ASSERT(scr != NULL && signal != NULL);
uint32_t start_bit;
uint32_t val;
irq_state_t state;
status_t ret;
if (scr_is_locked(scr, signal)) {
return SDRV_SCR_LOCKED;
}
start_bit = signal->start_bit & BITFIELD_POS_MSK;
ret = SDRV_SCR_CANNOT_LOCK;
switch (signal->type) {
case TYPE_L16:
if (start_bit < 16) {
state = arch_irq_save();
val = _scr_read_reg(scr->base, signal);
val |= BIT_MASK(signal->width) << (start_bit + 16);
_scr_write_reg(scr->base, signal, val);
arch_irq_restore(state);
ret = SDRV_STATUS_OK;
}
break;
case TYPE_L31:
if (start_bit < 31) {
state = arch_irq_save();
val = _scr_read_reg(scr->base, signal);
val |= 1ul << 31;
_scr_write_reg(scr->base, signal, val);
arch_irq_restore(state);
ret = SDRV_STATUS_OK;
}
break;
default:
break;
}
return ret;
}
bool scr_is_locked(const sdrv_scr_t *scr, const scr_signal_t *signal)
{
ASSERT(scr != NULL && signal != NULL);
bool locked = false;
uint32_t val = _scr_read_reg(scr->base, signal);
uint16_t start_bit = signal->start_bit & BITFIELD_POS_MSK;
switch (signal->type) {
case TYPE_L16:
if (start_bit < 16)
locked = !!(val & (1ul << (start_bit + 16)));
break;
case TYPE_L31:
if (start_bit < 31)
locked = !!(val & (1ul << 31));
break;
default:
break;
}
return locked;
}