/** * @file sdrv_scr.c * @brief Semidrive Status and Controller Register driver * * @copyright Copyright (c) 2022 Semidrive Semiconductor. * All rights reserved. */ #include #include #include #include #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; }