github.com/f-secure-foundry/tamago@v0.0.0-20220307101044-d73fcdd7f11b/board/f-secure/usbarmory/mark-two/ble.go (about) 1 // USB armory Mk II support for tamago/arm 2 // https://github.com/f-secure-foundry/tamago 3 // 4 // Copyright (c) F-Secure Corporation 5 // https://foundry.f-secure.com 6 // 7 // Use of this source code is governed by the license 8 // that can be found in the LICENSE file. 9 10 package usbarmory 11 12 import ( 13 "errors" 14 "sync" 15 "time" 16 17 "github.com/f-secure-foundry/tamago/bits" 18 "github.com/f-secure-foundry/tamago/soc/imx6" 19 ) 20 21 // BLE module configuration constants. 22 // 23 // On the USB armory Mk II a u-blox ANNA-B112 Bluetooth module is connected as 24 // illustrated in the following constants. 25 // 26 // On the USB armory Mk II β revision, due to an errata, the RTS/CTS signals 27 // are connected inverted on the Bluetooth module side. This is automatically 28 // handled with a workaround by the RTS() and CTS() functions, which use the 29 // lines as GPIOs to invert their direction. 30 const ( 31 // BT_UART_TX (UART1_TX_DATA) 32 IOMUXC_SW_MUX_CTL_PAD_UART1_TX_DATA = 0x020e0084 33 IOMUXC_SW_PAD_CTL_PAD_UART1_TX_DATA = 0x020e0310 34 35 // BT_UART_RX (UART1_RX_DATA) 36 IOMUXC_SW_MUX_CTL_PAD_UART1_RX_DATA = 0x020e0088 37 IOMUXC_SW_PAD_CTL_PAD_UART1_RX_DATA = 0x020e0314 38 IOMUXC_UART1_RX_DATA_SELECT_INPUT = 0x020e0624 39 DAISY_UART1_RX_DATA = 0b11 40 41 // BT_UART_CTS (UART1_CTS_B) 42 IOMUXC_SW_MUX_CTL_PAD_UART1_CTS_B = 0x020e008c 43 IOMUXC_SW_PAD_CTL_PAD_UART1_CTS_B = 0x020e0318 44 45 // BT_UART_RTS (UART1_RTS_B) 46 IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO07 = 0x020e0078 47 IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO07 = 0x020e0304 48 IOMUXC_UART1_RTS_B_SELECT_INPUT = 0x020e0620 49 UART1_RTS_B_MODE = 8 50 DAISY_GPIO1_IO07 = 0b01 51 52 // BT_UART_DSR (GPIO1_IO24) 53 IOMUXC_SW_MUX_CTL_PAD_UART3_TX_DATA = 0x020e00a4 54 IOMUXC_SW_PAD_CTL_PAD_UART3_TX_DATA = 0x020e0330 55 56 // BT_UART_DTR (GPIO1_IO25) 57 IOMUXC_SW_MUX_CTL_PAD_UART3_RX_DATA = 0x020e00a8 58 IOMUXC_SW_PAD_CTL_PAD_UART3_RX_DATA = 0x020e0334 59 60 // BT_SWDCLK 61 IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO04 = 0x020e006c 62 IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO04 = 0x020e02f8 63 64 // BT_SWDIO 65 IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO06 = 0x020e0074 66 IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO06 = 0x020e0300 67 68 // BT_RESET 69 BT_RESET = 9 70 IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO09 = 0x020e0080 71 IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO09 = 0x020e030c 72 73 // BT_SWITCH_1 (GPIO1_IO27) 74 BT_SWITCH_1 = 27 75 IOMUXC_SW_MUX_CTL_PAD_UART3_RTS_B = 0x020e00b0 76 IOMUXC_SW_PAD_CTL_PAD_UART3_RTS_B = 0x020e033c 77 78 // BT_SWITCH_2 (GPIO1_IO26) 79 BT_SWITCH_2 = 26 80 IOMUXC_SW_MUX_CTL_PAD_UART3_CTS_B = 0x020e00ac 81 IOMUXC_SW_PAD_CTL_PAD_UART3_CTS_B = 0x020e0338 82 83 DEFAULT_MODE = 0 84 GPIO_MODE = 5 85 86 RESET_GRACE_TIME = 1 * time.Second 87 ) 88 89 func configureBLEPad(mux uint32, pad uint32, daisy uint32, mode uint32, ctl uint32) (p *imx6.Pad) { 90 var err error 91 92 p, err = imx6.NewPad(mux, pad, daisy) 93 94 if err != nil { 95 panic(err) 96 } 97 98 p.Mode(mode) 99 p.Ctl(ctl) 100 101 return 102 } 103 104 func configureBLEGPIO(num int, instance int, mux uint32, pad uint32, ctl uint32) (gpio *imx6.GPIO) { 105 var err error 106 107 gpio, err = imx6.NewGPIO(num, instance, mux, pad) 108 109 if err != nil { 110 panic(err) 111 } 112 113 gpio.Pad.Mode(GPIO_MODE) 114 gpio.Pad.Ctl(ctl) 115 gpio.Out() 116 117 return 118 } 119 120 // ANNA implements the interface to the ANNA-B112 module for serial 121 // communication, reset and mode select. 122 type ANNA struct { 123 sync.Mutex 124 125 UART *imx6.UART 126 127 reset *imx6.GPIO 128 switch1 *imx6.GPIO 129 switch2 *imx6.GPIO 130 131 // On β revisions RTS/CTS are implemented as GPIO due to errata. 132 errata bool 133 rts *imx6.GPIO 134 cts *imx6.GPIO 135 } 136 137 // BLE module instance 138 var BLE = &ANNA{} 139 140 // Init initializes, in normal mode, a BLE module instance. 141 func (ble *ANNA) Init() (err error) { 142 ble.Lock() 143 defer ble.Unlock() 144 145 BLE.UART = imx6.UART1 146 147 ctl := uint32(0) 148 bits.Set(&ctl, imx6.SW_PAD_CTL_HYS) 149 bits.Set(&ctl, imx6.SW_PAD_CTL_PUE) 150 bits.Set(&ctl, imx6.SW_PAD_CTL_PKE) 151 152 bits.SetN(&ctl, imx6.SW_PAD_CTL_PUS, 0b11, imx6.SW_PAD_CTL_PUS_PULL_UP_100K) 153 bits.SetN(&ctl, imx6.SW_PAD_CTL_SPEED, 0b11, imx6.SW_PAD_CTL_SPEED_100MHZ) 154 bits.SetN(&ctl, imx6.SW_PAD_CTL_DSE, 0b111, imx6.SW_PAD_CTL_DSE_2_R0_6) 155 156 // BT_UART_TX 157 configureBLEPad(IOMUXC_SW_MUX_CTL_PAD_UART1_TX_DATA, 158 IOMUXC_SW_PAD_CTL_PAD_UART1_TX_DATA, 159 0, DEFAULT_MODE, ctl) 160 161 // BT_UART_RX 162 pad := configureBLEPad(IOMUXC_SW_MUX_CTL_PAD_UART1_RX_DATA, 163 IOMUXC_SW_PAD_CTL_PAD_UART1_RX_DATA, 164 IOMUXC_UART1_RX_DATA_SELECT_INPUT, 165 DEFAULT_MODE, ctl) 166 pad.Select(DAISY_UART1_RX_DATA) 167 168 switch Model() { 169 case "UA-MKII-β": 170 BLE.errata = true 171 172 // On β BT_UART_RTS is set to GPIO for CTS due to errata. 173 BLE.cts = configureBLEGPIO(7, 1, 174 IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO07, 175 IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO07, 176 ctl) 177 BLE.cts.Out() 178 179 bits.SetN(&ctl, imx6.SW_PAD_CTL_PUS, 0b11, imx6.SW_PAD_CTL_PUS_PULL_DOWN_100K) 180 181 // On β BT_UART_CTS is set to GPIO for RTS due to errata. 182 BLE.rts = configureBLEGPIO(18, 1, 183 IOMUXC_SW_MUX_CTL_PAD_UART1_CTS_B, 184 IOMUXC_SW_PAD_CTL_PAD_UART1_CTS_B, 185 ctl) 186 BLE.rts.In() 187 188 BLE.UART.Flow = false 189 default: 190 // BT_UART_CTS 191 pad = configureBLEPad(IOMUXC_SW_MUX_CTL_PAD_UART1_CTS_B, 192 IOMUXC_SW_PAD_CTL_PAD_UART1_CTS_B, 193 0, DEFAULT_MODE, ctl) 194 195 bits.SetN(&ctl, imx6.SW_PAD_CTL_PUS, 0b11, imx6.SW_PAD_CTL_PUS_PULL_DOWN_100K) 196 197 // BT_UART_RTS 198 pad = configureBLEPad(IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO07, 199 IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO07, 200 IOMUXC_UART1_RTS_B_SELECT_INPUT, 201 UART1_RTS_B_MODE, ctl) 202 pad.Select(DAISY_GPIO1_IO07) 203 204 BLE.UART.Flow = true 205 } 206 207 bits.SetN(&ctl, imx6.SW_PAD_CTL_PUS, 0b11, imx6.SW_PAD_CTL_PUS_PULL_UP_22K) 208 bits.SetN(&ctl, imx6.SW_PAD_CTL_SPEED, 0b11, imx6.SW_PAD_CTL_SPEED_50MHZ) 209 bits.SetN(&ctl, imx6.SW_PAD_CTL_DSE, 0b111, imx6.SW_PAD_CTL_DSE_2_R0_4) 210 211 // BT_UART_DSR 212 configureBLEPad(IOMUXC_SW_MUX_CTL_PAD_UART3_TX_DATA, 213 IOMUXC_SW_PAD_CTL_PAD_UART3_TX_DATA, 214 0, ctl, GPIO_MODE) 215 216 // BT_SWDCLK 217 configureBLEPad(IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO04, 218 IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO04, 219 0, GPIO_MODE, ctl) 220 221 // BT_SWDIO 222 configureBLEPad(IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO06, 223 IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO06, 224 0, GPIO_MODE, ctl) 225 226 // BT_RESET 227 BLE.reset = configureBLEGPIO(BT_RESET, 1, 228 IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO09, 229 IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO09, 230 ctl) 231 232 // BT_SWITCH_1 233 BLE.switch1 = configureBLEGPIO(BT_SWITCH_1, 1, 234 IOMUXC_SW_MUX_CTL_PAD_UART3_RTS_B, 235 IOMUXC_SW_PAD_CTL_PAD_UART3_RTS_B, 236 ctl) 237 238 // BT_SWITCH_2 239 BLE.switch2 = configureBLEGPIO(BT_SWITCH_2, 1, 240 IOMUXC_SW_MUX_CTL_PAD_UART3_CTS_B, 241 IOMUXC_SW_PAD_CTL_PAD_UART3_CTS_B, 242 ctl) 243 244 ctl = 0 245 bits.SetN(&ctl, imx6.SW_PAD_CTL_DSE, 0b111, imx6.SW_PAD_CTL_DSE_2_R0_4) 246 bits.Set(&ctl, imx6.SW_PAD_CTL_HYS) 247 248 // BT_UART_DTR 249 configureBLEPad(IOMUXC_SW_MUX_CTL_PAD_UART3_RX_DATA, 250 IOMUXC_SW_PAD_CTL_PAD_UART3_RX_DATA, 251 0, GPIO_MODE, ctl) 252 253 BLE.UART.Init() 254 255 // reset in normal mode 256 BLE.switch1.High() 257 BLE.switch2.High() 258 BLE.reset.Low() 259 defer BLE.reset.High() 260 261 return 262 } 263 264 // RTS returns whether the BLE module allows to send or not data, only useful 265 // on β boards when a workaround to the RTS/CTS errata is required. 266 func (ble *ANNA) RTS() (ready bool) { 267 if !BLE.errata { 268 return 269 } 270 271 return !ble.rts.Value() 272 } 273 274 // CTS signals the BLE module whether it is allowed to send or not data, only 275 // useful on β boards when a workaround to the RTS/CTS errata is required. 276 func (ble *ANNA) CTS(clear bool) { 277 if !BLE.errata { 278 return 279 } 280 281 if clear { 282 ble.cts.Low() 283 } else { 284 ble.cts.High() 285 } 286 } 287 288 // Reset the BLE module by toggling the RESET_N pin. 289 func (ble *ANNA) Reset() (err error) { 290 ble.Lock() 291 defer ble.Unlock() 292 293 if ble.reset == nil { 294 return errors.New("module is not initialized") 295 } 296 297 ble.reset.Low() 298 defer ble.reset.High() 299 300 time.Sleep(RESET_GRACE_TIME) 301 302 return 303 } 304 305 // Enter normal mode by driving high SWITCH_1 and SWITCH_2 during a module 306 // reset cycle. 307 func (ble *ANNA) NormalMode() (err error) { 308 ble.Lock() 309 defer ble.Unlock() 310 311 if ble.switch1 == nil || ble.switch2 == nil { 312 return errors.New("module is not initialized") 313 } 314 315 ble.switch1.High() 316 ble.switch2.High() 317 318 return ble.Reset() 319 } 320 321 // Enter bootloader mode by driving low SWITCH_1 and SWITCH_2 during a module 322 // reset cycle. 323 func (ble *ANNA) BootloaderMode() (err error) { 324 ble.Lock() 325 defer ble.Unlock() 326 327 if ble.switch1 == nil || ble.switch2 == nil { 328 return errors.New("module is not initialized") 329 } 330 331 ble.switch1.Low() 332 ble.switch2.Low() 333 334 return ble.Reset() 335 }