162 lines
4.5 KiB
C
162 lines
4.5 KiB
C
/*
|
|
* Copyright (c) 2016 Brian Swetland
|
|
*
|
|
* Use of this source code is governed by a MIT-style
|
|
* license that can be found in the LICENSE file or at
|
|
* https://opensource.org/licenses/MIT
|
|
*/
|
|
|
|
#include <app.h>
|
|
#include <lk/debug.h>
|
|
#include <lk/reg.h>
|
|
#include <kernel/thread.h>
|
|
#include <kernel/event.h>
|
|
#include <arch/arm/cm.h>
|
|
|
|
#include <driverlib/prcm.h>
|
|
#include <driverlib/rfc.h>
|
|
#include <driverlib/rf_mailbox.h>
|
|
#include <inc/hw_rfc_dbell.h>
|
|
|
|
#include <rf_patches/rf_patch_cpe_genfsk.h>
|
|
|
|
#include <platform/radio.h>
|
|
|
|
#define RADIO_POLLED_MODE 0
|
|
|
|
#define CPE0_MASK (IRQ_BOOT_DONE | IRQ_RX_OK | IRQ_LAST_COMMAND_DONE | IRQ_COMMAND_DONE)
|
|
|
|
static event_t ack_evt = EVENT_INITIAL_VALUE(ack_evt, 0, EVENT_FLAG_AUTOUNSIGNAL);
|
|
|
|
static event_t cpe0_evt = EVENT_INITIAL_VALUE(cpe0_evt, 0, EVENT_FLAG_AUTOUNSIGNAL);
|
|
|
|
void ti_cc_rfc_cpe_0_irq(void) {
|
|
arm_cm_irq_entry();
|
|
event_signal(&cpe0_evt, false);
|
|
|
|
// disable IRQ until thread handles and re-enables them in response to event
|
|
NVIC_DisableIRQ(rfc_cpe_0_IRQn);
|
|
|
|
// reschedule if we woke a thread (indicated by !signaled)
|
|
arm_cm_irq_exit(!cpe0_evt.signaled);
|
|
}
|
|
|
|
static inline uint32_t cpe0_reason(void) {
|
|
uint32_t n = HWREG(RFC_DBELL_BASE + RFC_DBELL_O_RFCPEIFG) & CPE0_MASK;
|
|
HWREG(RFC_DBELL_BASE + RFC_DBELL_O_RFCPEIFG) = ~n;
|
|
return n;
|
|
}
|
|
|
|
static inline uint32_t cpe0_wait_irq(void) {
|
|
NVIC_EnableIRQ(rfc_cpe_0_IRQn);
|
|
event_wait(&cpe0_evt);
|
|
return cpe0_reason();
|
|
}
|
|
|
|
void ti_cc_rfc_cpe_1_irq(void) {
|
|
arm_cm_irq_entry();
|
|
}
|
|
|
|
void ti_cc_rfc_cmd_ack_irq(void) {
|
|
arm_cm_irq_entry();
|
|
HWREG(RFC_DBELL_BASE + RFC_DBELL_O_RFACKIFG) = 0;
|
|
event_signal(&ack_evt, false);
|
|
// reschedule if we woke a thread (indicated by !signaled)
|
|
arm_cm_irq_exit(!ack_evt.signaled);
|
|
}
|
|
|
|
uint32_t radio_send_cmd(uint32_t cmd) {
|
|
#if RADIO_POLLED_MODE
|
|
while (HWREG(RFC_DBELL_BASE + RFC_DBELL_O_CMDR) != 0) {}
|
|
HWREG(RFC_DBELL_BASE + RFC_DBELL_O_RFACKIFG) = 0;
|
|
HWREG(RFC_DBELL_BASE + RFC_DBELL_O_CMDR) = cmd;
|
|
while (!HWREG(RFC_DBELL_BASE + RFC_DBELL_O_RFACKIFG)) {}
|
|
HWREG(RFC_DBELL_BASE + RFC_DBELL_O_RFACKIFG) = 0;
|
|
return HWREG(RFC_DBELL_BASE + RFC_DBELL_O_CMDSTA);
|
|
#else
|
|
while (HWREG(RFC_DBELL_BASE + RFC_DBELL_O_CMDR) != 0) {}
|
|
HWREG(RFC_DBELL_BASE + RFC_DBELL_O_RFACKIFG) = 0;
|
|
event_unsignal(&ack_evt);
|
|
HWREG(RFC_DBELL_BASE + RFC_DBELL_O_CMDR) = cmd;
|
|
event_wait(&ack_evt);
|
|
#endif
|
|
return HWREG(RFC_DBELL_BASE + RFC_DBELL_O_CMDSTA);
|
|
}
|
|
|
|
void radio_wait_cmd(uint16_t *status) {
|
|
uint32_t addr = (uint32_t) status;
|
|
uint16_t val;
|
|
#if RADIO_POLLED_MODE
|
|
for (;;) {
|
|
val = *REG16(addr);
|
|
if (val < 3) {
|
|
// idle, waiting to start, or running
|
|
thread_yield();
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
#else
|
|
for (;;) {
|
|
uint32_t x = cpe0_wait_irq();
|
|
val = *REG16(addr);
|
|
if (val > 3) {
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
if ((val != 0x0400) && (val != 0x3400)) {
|
|
dprintf(INFO, "Cmd Status %04x\n", val);
|
|
}
|
|
}
|
|
|
|
void radio_init(void) {
|
|
#if !RADIO_POLLED_MODE
|
|
// route all IRQs to CPE0
|
|
HWREG(RFC_DBELL_BASE + RFC_DBELL_O_RFCPEISL) = 0;
|
|
HWREG(RFC_DBELL_BASE + RFC_DBELL_O_RFCPEIEN) = CPE0_MASK;
|
|
|
|
// clear any pending
|
|
HWREG(RFC_DBELL_BASE + RFC_DBELL_O_RFCPEIFG) = 0;
|
|
HWREG(RFC_DBELL_BASE + RFC_DBELL_O_RFACKIFG) = 0;
|
|
|
|
//NVIC_EnableIRQ(rfc_cpe_0_IRQn);
|
|
//NVIC_EnableIRQ(rfc_cpe_1_IRQn);
|
|
NVIC_EnableIRQ(rfc_cmd_ack_IRQn);
|
|
#endif
|
|
|
|
// Power RF domain
|
|
PRCMPowerDomainOn(PRCM_DOMAIN_RFCORE);
|
|
while (PRCMPowerDomainStatus(PRCM_DOMAIN_RFCORE) != PRCM_DOMAIN_POWER_ON) ;
|
|
dprintf(INFO, "power on\n");
|
|
|
|
// enable the RF top clock
|
|
PRCMDomainEnable(PRCM_DOMAIN_RFCORE);
|
|
PRCMLoadSet();
|
|
dprintf(INFO, "top clock on\n");
|
|
|
|
// enable all RF sub clocks
|
|
RFCClockEnable();
|
|
dprintf(INFO, "clocks on\n");
|
|
|
|
thread_sleep(1000);
|
|
rf_patch_cpe_genfsk();
|
|
dprintf(INFO, "patched\n");
|
|
|
|
unsigned n = radio_send_cmd(IMM_CMD(CMD_PING, 0, 0));
|
|
dprintf(INFO, "RESPONSE %08x\n", n);
|
|
n = radio_send_cmd(IMM_CMD(CMD_PING, 0, 0));
|
|
dprintf(INFO, "RESPONSE %08x\n", n);
|
|
|
|
rf_op_fw_info_t fwinfo;
|
|
memset(&fwinfo, 0, sizeof(fwinfo));
|
|
fwinfo.cmd = CMD_GET_FW_INFO;
|
|
n = radio_send_cmd((uint32_t) &fwinfo);
|
|
dprintf(INFO, "FW %d %04x %04x %04x %04x\n",
|
|
n, fwinfo.version, fwinfo.free_ram_start,
|
|
fwinfo.free_ram_size, fwinfo.avail_rat_ch);
|
|
|
|
n = radio_send_cmd(IMM_CMD(CMD_START_RAT, 0, 0));
|
|
dprintf(INFO, "START RAT %d\n", n);
|
|
}
|