178 lines
4.2 KiB
C
178 lines
4.2 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;
|
|
}
|