1 /*
2  * Copyright (c) 2016 Brian Swetland
3  *
4  * Use of this source code is governed by a MIT-style
5  * license that can be found in the LICENSE file or at
6  * https://opensource.org/licenses/MIT
7  */
8 
9 #include <app.h>
10 #include <lk/debug.h>
11 #include <lk/reg.h>
12 #include <kernel/thread.h>
13 #include <kernel/event.h>
14 #include <arch/arm/cm.h>
15 
16 #include <driverlib/prcm.h>
17 #include <driverlib/rfc.h>
18 #include <driverlib/rf_mailbox.h>
19 #include <inc/hw_rfc_dbell.h>
20 
21 #include <rf_patches/rf_patch_cpe_genfsk.h>
22 
23 #include <platform/radio.h>
24 
25 #define RADIO_POLLED_MODE 0
26 
27 #define CPE0_MASK (IRQ_BOOT_DONE | IRQ_RX_OK | IRQ_LAST_COMMAND_DONE | IRQ_COMMAND_DONE)
28 
29 static event_t ack_evt = EVENT_INITIAL_VALUE(ack_evt, 0, EVENT_FLAG_AUTOUNSIGNAL);
30 
31 static event_t cpe0_evt = EVENT_INITIAL_VALUE(cpe0_evt, 0, EVENT_FLAG_AUTOUNSIGNAL);
32 
ti_cc_rfc_cpe_0_irq(void)33 void ti_cc_rfc_cpe_0_irq(void) {
34     arm_cm_irq_entry();
35     event_signal(&cpe0_evt, false);
36 
37     // disable IRQ until thread handles and re-enables them in response to event
38     NVIC_DisableIRQ(rfc_cpe_0_IRQn);
39 
40     // reschedule if we woke a thread (indicated by !signaled)
41     arm_cm_irq_exit(!cpe0_evt.signaled);
42 }
43 
cpe0_reason(void)44 static inline uint32_t cpe0_reason(void) {
45     uint32_t n = HWREG(RFC_DBELL_BASE + RFC_DBELL_O_RFCPEIFG) & CPE0_MASK;
46     HWREG(RFC_DBELL_BASE + RFC_DBELL_O_RFCPEIFG) = ~n;
47     return n;
48 }
49 
cpe0_wait_irq(void)50 static inline uint32_t cpe0_wait_irq(void) {
51     NVIC_EnableIRQ(rfc_cpe_0_IRQn);
52     event_wait(&cpe0_evt);
53     return cpe0_reason();
54 }
55 
ti_cc_rfc_cpe_1_irq(void)56 void ti_cc_rfc_cpe_1_irq(void) {
57     arm_cm_irq_entry();
58 }
59 
ti_cc_rfc_cmd_ack_irq(void)60 void ti_cc_rfc_cmd_ack_irq(void) {
61     arm_cm_irq_entry();
62     HWREG(RFC_DBELL_BASE + RFC_DBELL_O_RFACKIFG) = 0;
63     event_signal(&ack_evt, false);
64     // reschedule if we woke a thread (indicated by !signaled)
65     arm_cm_irq_exit(!ack_evt.signaled);
66 }
67 
radio_send_cmd(uint32_t cmd)68 uint32_t radio_send_cmd(uint32_t cmd) {
69 #if RADIO_POLLED_MODE
70     while (HWREG(RFC_DBELL_BASE + RFC_DBELL_O_CMDR) != 0) {}
71     HWREG(RFC_DBELL_BASE + RFC_DBELL_O_RFACKIFG) = 0;
72     HWREG(RFC_DBELL_BASE + RFC_DBELL_O_CMDR) = cmd;
73     while (!HWREG(RFC_DBELL_BASE + RFC_DBELL_O_RFACKIFG)) {}
74     HWREG(RFC_DBELL_BASE + RFC_DBELL_O_RFACKIFG) = 0;
75     return HWREG(RFC_DBELL_BASE + RFC_DBELL_O_CMDSTA);
76 #else
77     while (HWREG(RFC_DBELL_BASE + RFC_DBELL_O_CMDR) != 0) {}
78     HWREG(RFC_DBELL_BASE + RFC_DBELL_O_RFACKIFG) = 0;
79     event_unsignal(&ack_evt);
80     HWREG(RFC_DBELL_BASE + RFC_DBELL_O_CMDR) = cmd;
81     event_wait(&ack_evt);
82 #endif
83     return HWREG(RFC_DBELL_BASE + RFC_DBELL_O_CMDSTA);
84 }
85 
radio_wait_cmd(uint16_t * status)86 void radio_wait_cmd(uint16_t *status) {
87     uint32_t addr = (uint32_t) status;
88     uint16_t val;
89 #if RADIO_POLLED_MODE
90     for (;;) {
91         val = *REG16(addr);
92         if (val < 3) {
93             // idle, waiting to start, or running
94             thread_yield();
95         } else {
96             break;
97         }
98     }
99 #else
100     for (;;) {
101         uint32_t x = cpe0_wait_irq();
102         val = *REG16(addr);
103         if (val > 3) {
104             break;
105         }
106     }
107 #endif
108     if ((val != 0x0400) && (val != 0x3400)) {
109         dprintf(INFO, "Cmd Status %04x\n", val);
110     }
111 }
112 
radio_init(void)113 void radio_init(void) {
114 #if !RADIO_POLLED_MODE
115     // route all IRQs to CPE0
116     HWREG(RFC_DBELL_BASE + RFC_DBELL_O_RFCPEISL) = 0;
117     HWREG(RFC_DBELL_BASE + RFC_DBELL_O_RFCPEIEN) = CPE0_MASK;
118 
119     // clear any pending
120     HWREG(RFC_DBELL_BASE + RFC_DBELL_O_RFCPEIFG) = 0;
121     HWREG(RFC_DBELL_BASE + RFC_DBELL_O_RFACKIFG) = 0;
122 
123     //NVIC_EnableIRQ(rfc_cpe_0_IRQn);
124     //NVIC_EnableIRQ(rfc_cpe_1_IRQn);
125     NVIC_EnableIRQ(rfc_cmd_ack_IRQn);
126 #endif
127 
128     // Power RF domain
129     PRCMPowerDomainOn(PRCM_DOMAIN_RFCORE);
130     while (PRCMPowerDomainStatus(PRCM_DOMAIN_RFCORE) != PRCM_DOMAIN_POWER_ON) ;
131     dprintf(INFO, "power on\n");
132 
133     // enable the RF top clock
134     PRCMDomainEnable(PRCM_DOMAIN_RFCORE);
135     PRCMLoadSet();
136     dprintf(INFO, "top clock on\n");
137 
138     // enable all RF sub clocks
139     RFCClockEnable();
140     dprintf(INFO, "clocks on\n");
141 
142     thread_sleep(1000);
143     rf_patch_cpe_genfsk();
144     dprintf(INFO, "patched\n");
145 
146     unsigned n = radio_send_cmd(IMM_CMD(CMD_PING, 0, 0));
147     dprintf(INFO, "RESPONSE %08x\n", n);
148     n = radio_send_cmd(IMM_CMD(CMD_PING, 0, 0));
149     dprintf(INFO, "RESPONSE %08x\n", n);
150 
151     rf_op_fw_info_t fwinfo;
152     memset(&fwinfo, 0, sizeof(fwinfo));
153     fwinfo.cmd = CMD_GET_FW_INFO;
154     n = radio_send_cmd((uint32_t) &fwinfo);
155     dprintf(INFO, "FW %d %04x %04x %04x %04x\n",
156             n, fwinfo.version, fwinfo.free_ram_start,
157             fwinfo.free_ram_size, fwinfo.avail_rat_ch);
158 
159     n = radio_send_cmd(IMM_CMD(CMD_START_RAT, 0, 0));
160     dprintf(INFO, "START RAT %d\n", n);
161 }
162