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