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  }