diff --git a/doc/ip/pinmux/README.md b/doc/ip/pinmux/README.md index cdca3e759..65d5b72d5 100644 --- a/doc/ip/pinmux/README.md +++ b/doc/ip/pinmux/README.md @@ -12,166 +12,166 @@ The default value for all of these selectors is `'b10`. | Address | Pin output | Possible block outputs | |---------|------------|------------------------| -| 0x000 | `ser0_tx` | 0, `uart[0].tx` | -| 0x001 | `ser1_tx` | 0, `uart[1].tx`, `uart[2].tx` | -| 0x002 | `rs232_tx` | 0, `uart[2].tx` | -| 0x003 | `rs485_tx` | 0, `uart[2].tx` | -| 0x004 | `scl0` | 0, `i2c[0].scl` | -| 0x005 | `sda0` | 0, `i2c[0].sda` | -| 0x006 | `scl1` | 0, `i2c[1].scl` | -| 0x007 | `sda1` | 0, `i2c[1].sda` | -| 0x008 | `rph_g0` | 0, `i2c[0].sda`, `gpio[0].ios[0]` | -| 0x009 | `rph_g1` | 0, `i2c[0].scl`, `gpio[0].ios[1]` | -| 0x00a | `rph_g2_sda` | 0, `i2c[1].sda`, `gpio[0].ios[2]` | -| 0x00b | `rph_g3_scl` | 0, `i2c[1].scl`, `gpio[0].ios[3]` | -| 0x00c | `rph_g4` | 0, `gpio[0].ios[4]` | -| 0x00d | `rph_g5` | 0, `gpio[0].ios[5]` | -| 0x00e | `rph_g6` | 0, `gpio[0].ios[6]` | -| 0x00f | `rph_g7` | 0, `spi[1].cs[1]`, `gpio[0].ios[7]` | -| 0x010 | `rph_g8` | 0, `spi[1].cs[0]`, `gpio[0].ios[8]` | -| 0x011 | `rph_g9` | 0, `gpio[0].ios[9]` | -| 0x012 | `rph_g10` | 0, `spi[1].copi`, `gpio[0].ios[10]` | -| 0x013 | `rph_g11` | 0, `spi[1].sclk`, `gpio[0].ios[11]` | -| 0x014 | `rph_g12` | 0, `gpio[0].ios[12]`, `pwm_out[0]` | -| 0x015 | `rph_g13` | 0, `gpio[0].ios[13]`, `pwm_out[1]` | -| 0x016 | `rph_txd0` | 0, `uart[1].tx`, `gpio[0].ios[14]` | -| 0x017 | `rph_rxd0` | 0, `gpio[0].ios[15]` | -| 0x018 | `rph_g16` | 0, `spi[2].cs[2]`, `gpio[0].ios[16]` | -| 0x019 | `rph_g17` | 0, `spi[2].cs[1]`, `gpio[0].ios[17]` | -| 0x01a | `rph_g18` | 0, `spi[2].cs[0]`, `gpio[0].ios[18]`, `pwm_out[2]` | -| 0x01b | `rph_g19` | 0, `gpio[0].ios[19]`, `pwm_out[3]` | -| 0x01c | `rph_g20` | 0, `spi[2].copi`, `gpio[0].ios[20]`, `pwm_out[4]` | -| 0x01d | `rph_g21` | 0, `spi[2].sclk`, `gpio[0].ios[21]`, `pwm_out[5]` | -| 0x01e | `rph_g22` | 0, `gpio[0].ios[22]` | -| 0x01f | `rph_g23` | 0, `gpio[0].ios[23]` | -| 0x020 | `rph_g24` | 0, `gpio[0].ios[24]` | -| 0x021 | `rph_g25` | 0, `gpio[0].ios[25]` | -| 0x022 | `rph_g26` | 0, `gpio[0].ios[26]` | -| 0x023 | `rph_g27` | 0, `gpio[0].ios[27]` | -| 0x024 | `ah_tmpio0` | 0, `gpio[1].ios[0]` | -| 0x025 | `ah_tmpio1` | 0, `uart[1].tx`, `gpio[1].ios[1]` | -| 0x026 | `ah_tmpio2` | 0, `gpio[1].ios[2]` | -| 0x027 | `ah_tmpio3` | 0, `gpio[1].ios[3]`, `pwm_out[0]` | -| 0x028 | `ah_tmpio4` | 0, `gpio[1].ios[4]` | -| 0x029 | `ah_tmpio5` | 0, `gpio[1].ios[5]`, `pwm_out[1]` | -| 0x02a | `ah_tmpio6` | 0, `gpio[1].ios[6]`, `pwm_out[2]` | -| 0x02b | `ah_tmpio7` | 0, `gpio[1].ios[7]` | -| 0x02c | `ah_tmpio8` | 0, `gpio[1].ios[8]` | -| 0x02d | `ah_tmpio9` | 0, `gpio[1].ios[9]`, `pwm_out[3]` | -| 0x02e | `ah_tmpio10` | 0, `spi[1].cs[3]`, `gpio[1].ios[10]`, `pwm_out[4]` | -| 0x02f | `ah_tmpio11` | 0, `spi[1].copi`, `gpio[1].ios[11]`, `pwm_out[5]` | -| 0x030 | `ah_tmpio12` | 0, `gpio[1].ios[12]` | -| 0x031 | `ah_tmpio13` | 0, `spi[1].sclk`, `gpio[1].ios[13]` | -| 0x032 | `mb1` | 0, `spi[2].cs[3]` | -| 0x033 | `mb2` | 0, `spi[2].sclk` | -| 0x034 | `mb4` | 0, `spi[2].copi` | -| 0x035 | `mb5` | 0, `i2c[1].sda` | -| 0x036 | `mb6` | 0, `i2c[1].scl` | -| 0x037 | `mb7` | 0, `uart[1].tx` | -| 0x038 | `mb10` | 0, `pwm_out[0]` | -| 0x039 | `pmod0_1` | 0, `gpio[2].ios[0]`, `spi[1].cs[0]` | -| 0x03a | `pmod0_2` | 0, `gpio[2].ios[1]`, `spi[1].copi`, `pwm_out[1]`, `uart[1].tx` | -| 0x03b | `pmod0_3` | 0, `gpio[2].ios[2]`, `i2c[0].scl` | -| 0x03c | `pmod0_4` | 0, `gpio[2].ios[3]`, `spi[1].sclk`, `i2c[0].sda` | -| 0x03d | `pmod0_7` | 0, `gpio[2].ios[4]` | -| 0x03e | `pmod0_8` | 0, `gpio[2].ios[5]`, `pwm_out[2]` | -| 0x03f | `pmod0_9` | 0, `gpio[2].ios[6]`, `spi[1].cs[1]` | -| 0x040 | `pmod0_10` | 0, `gpio[2].ios[7]`, `spi[1].cs[2]` | -| 0x041 | `pmod1_1` | 0, `gpio[3].ios[0]`, `spi[2].cs[0]` | -| 0x042 | `pmod1_2` | 0, `gpio[3].ios[1]`, `spi[2].copi`, `pwm_out[3]`, `uart[2].tx` | -| 0x043 | `pmod1_3` | 0, `gpio[3].ios[2]`, `i2c[1].scl` | -| 0x044 | `pmod1_4` | 0, `gpio[3].ios[3]`, `spi[2].sclk`, `i2c[1].sda` | -| 0x045 | `pmod1_7` | 0, `gpio[3].ios[4]` | -| 0x046 | `pmod1_8` | 0, `gpio[3].ios[5]`, `pwm_out[4]` | -| 0x047 | `pmod1_9` | 0, `gpio[3].ios[6]`, `spi[2].cs[1]` | -| 0x048 | `pmod1_10` | 0, `gpio[3].ios[7]`, `spi[2].cs[2]` | -| 0x049 | `pmodc_1` | 0, `gpio[4].ios[0]` | -| 0x04a | `pmodc_2` | 0, `gpio[4].ios[1]` | -| 0x04b | `pmodc_3` | 0, `gpio[4].ios[2]` | -| 0x04c | `pmodc_4` | 0, `gpio[4].ios[3]` | -| 0x04d | `pmodc_5` | 0, `gpio[4].ios[4]` | -| 0x04e | `pmodc_6` | 0, `gpio[4].ios[5]` | -| 0x04f | `appspi_d0` | 0, `spi[0].copi` | -| 0x050 | `appspi_clk` | 0, `spi[0].sclk` | -| 0x051 | `appspi_cs` | 0, `spi[0].cs[0]` | -| 0x052 | `microsd_cmd` | 0, `spi[0].copi` | -| 0x053 | `microsd_clk` | 0, `spi[0].sclk` | -| 0x054 | `microsd_dat3` | 0, `spi[0].cs[1]` | +| 0x000 | `ser0_tx` | 0, `uart_0_tx` | +| 0x001 | `ser1_tx` | 0, `uart_1_tx`, `uart_2_tx` | +| 0x002 | `rs232_tx` | 0, `uart_2_tx` | +| 0x003 | `rs485_tx` | 0, `uart_2_tx` | +| 0x004 | `scl0` | 0, `i2c_0_scl` | +| 0x005 | `sda0` | 0, `i2c_0_sda` | +| 0x006 | `scl1` | 0, `i2c_1_scl` | +| 0x007 | `sda1` | 0, `i2c_1_sda` | +| 0x008 | `rph_g0` | 0, `i2c_0_sda`, `gpio_0_ios_0` | +| 0x009 | `rph_g1` | 0, `i2c_0_scl`, `gpio_0_ios_1` | +| 0x00a | `rph_g2_sda` | 0, `i2c_1_sda`, `gpio_0_ios_2` | +| 0x00b | `rph_g3_scl` | 0, `i2c_1_scl`, `gpio_0_ios_3` | +| 0x00c | `rph_g4` | 0, `gpio_0_ios_4` | +| 0x00d | `rph_g5` | 0, `gpio_0_ios_5` | +| 0x00e | `rph_g6` | 0, `gpio_0_ios_6` | +| 0x00f | `rph_g7` | 0, `spi_1_cs_1`, `gpio_0_ios_7` | +| 0x010 | `rph_g8` | 0, `spi_1_cs_0`, `gpio_0_ios_8` | +| 0x011 | `rph_g9` | 0, `gpio_0_ios_9` | +| 0x012 | `rph_g10` | 0, `spi_1_copi`, `gpio_0_ios_10` | +| 0x013 | `rph_g11` | 0, `spi_1_sclk`, `gpio_0_ios_11` | +| 0x014 | `rph_g12` | 0, `gpio_0_ios_12`, `pwm_out_0` | +| 0x015 | `rph_g13` | 0, `gpio_0_ios_13`, `pwm_out_1` | +| 0x016 | `rph_txd0` | 0, `uart_1_tx`, `gpio_0_ios_14` | +| 0x017 | `rph_rxd0` | 0, `gpio_0_ios_15` | +| 0x018 | `rph_g16` | 0, `spi_2_cs_2`, `gpio_0_ios_16` | +| 0x019 | `rph_g17` | 0, `spi_2_cs_1`, `gpio_0_ios_17` | +| 0x01a | `rph_g18` | 0, `spi_2_cs_0`, `gpio_0_ios_18`, `pwm_out_2` | +| 0x01b | `rph_g19` | 0, `gpio_0_ios_19`, `pwm_out_3` | +| 0x01c | `rph_g20` | 0, `spi_2_copi`, `gpio_0_ios_20`, `pwm_out_4` | +| 0x01d | `rph_g21` | 0, `spi_2_sclk`, `gpio_0_ios_21`, `pwm_out_5` | +| 0x01e | `rph_g22` | 0, `gpio_0_ios_22` | +| 0x01f | `rph_g23` | 0, `gpio_0_ios_23` | +| 0x020 | `rph_g24` | 0, `gpio_0_ios_24` | +| 0x021 | `rph_g25` | 0, `gpio_0_ios_25` | +| 0x022 | `rph_g26` | 0, `gpio_0_ios_26` | +| 0x023 | `rph_g27` | 0, `gpio_0_ios_27` | +| 0x024 | `ah_tmpio0` | 0, `gpio_1_ios_0` | +| 0x025 | `ah_tmpio1` | 0, `uart_1_tx`, `gpio_1_ios_1` | +| 0x026 | `ah_tmpio2` | 0, `gpio_1_ios_2` | +| 0x027 | `ah_tmpio3` | 0, `gpio_1_ios_3`, `pwm_out_0` | +| 0x028 | `ah_tmpio4` | 0, `gpio_1_ios_4` | +| 0x029 | `ah_tmpio5` | 0, `gpio_1_ios_5`, `pwm_out_1` | +| 0x02a | `ah_tmpio6` | 0, `gpio_1_ios_6`, `pwm_out_2` | +| 0x02b | `ah_tmpio7` | 0, `gpio_1_ios_7` | +| 0x02c | `ah_tmpio8` | 0, `gpio_1_ios_8` | +| 0x02d | `ah_tmpio9` | 0, `gpio_1_ios_9`, `pwm_out_3` | +| 0x02e | `ah_tmpio10` | 0, `spi_1_cs_3`, `gpio_1_ios_10`, `pwm_out_4` | +| 0x02f | `ah_tmpio11` | 0, `spi_1_copi`, `gpio_1_ios_11`, `pwm_out_5` | +| 0x030 | `ah_tmpio12` | 0, `gpio_1_ios_12` | +| 0x031 | `ah_tmpio13` | 0, `spi_1_sclk`, `gpio_1_ios_13` | +| 0x032 | `mb1` | 0, `spi_2_cs_3` | +| 0x033 | `mb2` | 0, `spi_2_sclk` | +| 0x034 | `mb4` | 0, `spi_2_copi` | +| 0x035 | `mb5` | 0, `i2c_1_sda` | +| 0x036 | `mb6` | 0, `i2c_1_scl` | +| 0x037 | `mb7` | 0, `uart_1_tx` | +| 0x038 | `mb10` | 0, `pwm_out_0` | +| 0x039 | `pmod0_1` | 0, `gpio_2_ios_0`, `spi_1_cs_0` | +| 0x03a | `pmod0_2` | 0, `gpio_2_ios_1`, `spi_1_copi`, `pwm_out_1`, `uart_1_tx` | +| 0x03b | `pmod0_3` | 0, `gpio_2_ios_2`, `i2c_0_scl` | +| 0x03c | `pmod0_4` | 0, `gpio_2_ios_3`, `spi_1_sclk`, `i2c_0_sda` | +| 0x03d | `pmod0_7` | 0, `gpio_2_ios_4` | +| 0x03e | `pmod0_8` | 0, `gpio_2_ios_5`, `pwm_out_2` | +| 0x03f | `pmod0_9` | 0, `gpio_2_ios_6`, `spi_1_cs_1` | +| 0x040 | `pmod0_10` | 0, `gpio_2_ios_7`, `spi_1_cs_2` | +| 0x041 | `pmod1_1` | 0, `gpio_3_ios_0`, `spi_2_cs_0` | +| 0x042 | `pmod1_2` | 0, `gpio_3_ios_1`, `spi_2_copi`, `pwm_out_3`, `uart_2_tx` | +| 0x043 | `pmod1_3` | 0, `gpio_3_ios_2`, `i2c_1_scl` | +| 0x044 | `pmod1_4` | 0, `gpio_3_ios_3`, `spi_2_sclk`, `i2c_1_sda` | +| 0x045 | `pmod1_7` | 0, `gpio_3_ios_4` | +| 0x046 | `pmod1_8` | 0, `gpio_3_ios_5`, `pwm_out_4` | +| 0x047 | `pmod1_9` | 0, `gpio_3_ios_6`, `spi_2_cs_1` | +| 0x048 | `pmod1_10` | 0, `gpio_3_ios_7`, `spi_2_cs_2` | +| 0x049 | `pmodc_1` | 0, `gpio_4_ios_0` | +| 0x04a | `pmodc_2` | 0, `gpio_4_ios_1` | +| 0x04b | `pmodc_3` | 0, `gpio_4_ios_2` | +| 0x04c | `pmodc_4` | 0, `gpio_4_ios_3` | +| 0x04d | `pmodc_5` | 0, `gpio_4_ios_4` | +| 0x04e | `pmodc_6` | 0, `gpio_4_ios_5` | +| 0x04f | `appspi_d0` | 0, `spi_0_copi` | +| 0x050 | `appspi_clk` | 0, `spi_0_sclk` | +| 0x051 | `appspi_cs` | 0, `spi_0_cs_0` | +| 0x052 | `microsd_cmd` | 0, `spi_0_copi` | +| 0x053 | `microsd_clk` | 0, `spi_0_sclk` | +| 0x054 | `microsd_dat3` | 0, `spi_0_cs_1` | Besides the output pin selectors, there are also selectors for which pin should drive block inputs: | Address | Block input | Possible pin inputs | |---------|-------------|---------------------| -| 0x800 | `gpio[0].ios[0]` | 0, `rph_g0` | -| 0x801 | `gpio[0].ios[1]` | 0, `rph_g1` | -| 0x802 | `gpio[0].ios[2]` | 0, `rph_g2_sda` | -| 0x803 | `gpio[0].ios[3]` | 0, `rph_g3_scl` | -| 0x804 | `gpio[0].ios[4]` | 0, `rph_g4` | -| 0x805 | `gpio[0].ios[5]` | 0, `rph_g5` | -| 0x806 | `gpio[0].ios[6]` | 0, `rph_g6` | -| 0x807 | `gpio[0].ios[7]` | 0, `rph_g7` | -| 0x808 | `gpio[0].ios[8]` | 0, `rph_g8` | -| 0x809 | `gpio[0].ios[9]` | 0, `rph_g9` | -| 0x80a | `gpio[0].ios[10]` | 0, `rph_g10` | -| 0x80b | `gpio[0].ios[11]` | 0, `rph_g11` | -| 0x80c | `gpio[0].ios[12]` | 0, `rph_g12` | -| 0x80d | `gpio[0].ios[13]` | 0, `rph_g13` | -| 0x80e | `gpio[0].ios[14]` | 0, `rph_txd0` | -| 0x80f | `gpio[0].ios[15]` | 0, `rph_rxd0` | -| 0x810 | `gpio[0].ios[16]` | 0, `rph_g16` | -| 0x811 | `gpio[0].ios[17]` | 0, `rph_g17` | -| 0x812 | `gpio[0].ios[18]` | 0, `rph_g18` | -| 0x813 | `gpio[0].ios[19]` | 0, `rph_g19` | -| 0x814 | `gpio[0].ios[20]` | 0, `rph_g20` | -| 0x815 | `gpio[0].ios[21]` | 0, `rph_g21` | -| 0x816 | `gpio[0].ios[22]` | 0, `rph_g22` | -| 0x817 | `gpio[0].ios[23]` | 0, `rph_g23` | -| 0x818 | `gpio[0].ios[24]` | 0, `rph_g24` | -| 0x819 | `gpio[0].ios[25]` | 0, `rph_g25` | -| 0x81a | `gpio[0].ios[26]` | 0, `rph_g26` | -| 0x81b | `gpio[0].ios[27]` | 0, `rph_g27` | -| 0x81c | `gpio[1].ios[0]` | 0, `ah_tmpio0` | -| 0x81d | `gpio[1].ios[1]` | 0, `ah_tmpio1` | -| 0x81e | `gpio[1].ios[2]` | 0, `ah_tmpio2` | -| 0x81f | `gpio[1].ios[3]` | 0, `ah_tmpio3` | -| 0x820 | `gpio[1].ios[4]` | 0, `ah_tmpio4` | -| 0x821 | `gpio[1].ios[5]` | 0, `ah_tmpio5` | -| 0x822 | `gpio[1].ios[6]` | 0, `ah_tmpio6` | -| 0x823 | `gpio[1].ios[7]` | 0, `ah_tmpio7` | -| 0x824 | `gpio[1].ios[8]` | 0, `ah_tmpio8` | -| 0x825 | `gpio[1].ios[9]` | 0, `ah_tmpio9` | -| 0x826 | `gpio[1].ios[10]` | 0, `ah_tmpio10` | -| 0x827 | `gpio[1].ios[11]` | 0, `ah_tmpio11` | -| 0x828 | `gpio[1].ios[12]` | 0, `ah_tmpio12` | -| 0x829 | `gpio[1].ios[13]` | 0, `ah_tmpio13` | -| 0x82a | `gpio[2].ios[0]` | 0, `pmod0_1` | -| 0x82b | `gpio[2].ios[1]` | 0, `pmod0_2` | -| 0x82c | `gpio[2].ios[2]` | 0, `pmod0_3` | -| 0x82d | `gpio[2].ios[3]` | 0, `pmod0_4` | -| 0x82e | `gpio[2].ios[4]` | 0, `pmod0_7` | -| 0x82f | `gpio[2].ios[5]` | 0, `pmod0_8` | -| 0x830 | `gpio[2].ios[6]` | 0, `pmod0_9` | -| 0x831 | `gpio[2].ios[7]` | 0, `pmod0_10` | -| 0x832 | `gpio[3].ios[0]` | 0, `pmod1_1` | -| 0x833 | `gpio[3].ios[1]` | 0, `pmod1_2` | -| 0x834 | `gpio[3].ios[2]` | 0, `pmod1_3` | -| 0x835 | `gpio[3].ios[3]` | 0, `pmod1_4` | -| 0x836 | `gpio[3].ios[4]` | 0, `pmod1_7` | -| 0x837 | `gpio[3].ios[5]` | 0, `pmod1_8` | -| 0x838 | `gpio[3].ios[6]` | 0, `pmod1_9` | -| 0x839 | `gpio[3].ios[7]` | 0, `pmod1_10` | -| 0x83a | `gpio[4].ios[0]` | 0, `pmodc_1` | -| 0x83b | `gpio[4].ios[1]` | 0, `pmodc_2` | -| 0x83c | `gpio[4].ios[2]` | 0, `pmodc_3` | -| 0x83d | `gpio[4].ios[3]` | 0, `pmodc_4` | -| 0x83e | `gpio[4].ios[4]` | 0, `pmodc_5` | -| 0x83f | `gpio[4].ios[5]` | 0, `pmodc_6` | -| 0x840 | `uart[0].rx` | 1, `ser0_rx` | -| 0x841 | `uart[1].rx` | 1, `ser1_rx`, `rph_rxd0`, `ah_tmpio0`, `mb8`, `pmod0_3` | -| 0x842 | `uart[2].rx` | 1, `ser1_rx`, `rs232_rx`, `rs485_rx`, `pmod1_3` | -| 0x843 | `spi[0].cipo` | 0, `appspi_d1`, `microsd_dat0` | -| 0x844 | `spi[1].cipo` | 0, `rph_g9`, `ah_tmpio12`, `pmod0_3` | -| 0x845 | `spi[2].cipo` | 0, `rph_g19`, `mb3`, `pmod1_3` | +| 0x800 | `gpio_0_ios_0` | 0, `rph_g0` | +| 0x801 | `gpio_0_ios_1` | 0, `rph_g1` | +| 0x802 | `gpio_0_ios_2` | 0, `rph_g2_sda` | +| 0x803 | `gpio_0_ios_3` | 0, `rph_g3_scl` | +| 0x804 | `gpio_0_ios_4` | 0, `rph_g4` | +| 0x805 | `gpio_0_ios_5` | 0, `rph_g5` | +| 0x806 | `gpio_0_ios_6` | 0, `rph_g6` | +| 0x807 | `gpio_0_ios_7` | 0, `rph_g7` | +| 0x808 | `gpio_0_ios_8` | 0, `rph_g8` | +| 0x809 | `gpio_0_ios_9` | 0, `rph_g9` | +| 0x80a | `gpio_0_ios_10` | 0, `rph_g10` | +| 0x80b | `gpio_0_ios_11` | 0, `rph_g11` | +| 0x80c | `gpio_0_ios_12` | 0, `rph_g12` | +| 0x80d | `gpio_0_ios_13` | 0, `rph_g13` | +| 0x80e | `gpio_0_ios_14` | 0, `rph_txd0` | +| 0x80f | `gpio_0_ios_15` | 0, `rph_rxd0` | +| 0x810 | `gpio_0_ios_16` | 0, `rph_g16` | +| 0x811 | `gpio_0_ios_17` | 0, `rph_g17` | +| 0x812 | `gpio_0_ios_18` | 0, `rph_g18` | +| 0x813 | `gpio_0_ios_19` | 0, `rph_g19` | +| 0x814 | `gpio_0_ios_20` | 0, `rph_g20` | +| 0x815 | `gpio_0_ios_21` | 0, `rph_g21` | +| 0x816 | `gpio_0_ios_22` | 0, `rph_g22` | +| 0x817 | `gpio_0_ios_23` | 0, `rph_g23` | +| 0x818 | `gpio_0_ios_24` | 0, `rph_g24` | +| 0x819 | `gpio_0_ios_25` | 0, `rph_g25` | +| 0x81a | `gpio_0_ios_26` | 0, `rph_g26` | +| 0x81b | `gpio_0_ios_27` | 0, `rph_g27` | +| 0x81c | `gpio_1_ios_0` | 0, `ah_tmpio0` | +| 0x81d | `gpio_1_ios_1` | 0, `ah_tmpio1` | +| 0x81e | `gpio_1_ios_2` | 0, `ah_tmpio2` | +| 0x81f | `gpio_1_ios_3` | 0, `ah_tmpio3` | +| 0x820 | `gpio_1_ios_4` | 0, `ah_tmpio4` | +| 0x821 | `gpio_1_ios_5` | 0, `ah_tmpio5` | +| 0x822 | `gpio_1_ios_6` | 0, `ah_tmpio6` | +| 0x823 | `gpio_1_ios_7` | 0, `ah_tmpio7` | +| 0x824 | `gpio_1_ios_8` | 0, `ah_tmpio8` | +| 0x825 | `gpio_1_ios_9` | 0, `ah_tmpio9` | +| 0x826 | `gpio_1_ios_10` | 0, `ah_tmpio10` | +| 0x827 | `gpio_1_ios_11` | 0, `ah_tmpio11` | +| 0x828 | `gpio_1_ios_12` | 0, `ah_tmpio12` | +| 0x829 | `gpio_1_ios_13` | 0, `ah_tmpio13` | +| 0x82a | `gpio_2_ios_0` | 0, `pmod0_1` | +| 0x82b | `gpio_2_ios_1` | 0, `pmod0_2` | +| 0x82c | `gpio_2_ios_2` | 0, `pmod0_3` | +| 0x82d | `gpio_2_ios_3` | 0, `pmod0_4` | +| 0x82e | `gpio_2_ios_4` | 0, `pmod0_7` | +| 0x82f | `gpio_2_ios_5` | 0, `pmod0_8` | +| 0x830 | `gpio_2_ios_6` | 0, `pmod0_9` | +| 0x831 | `gpio_2_ios_7` | 0, `pmod0_10` | +| 0x832 | `gpio_3_ios_0` | 0, `pmod1_1` | +| 0x833 | `gpio_3_ios_1` | 0, `pmod1_2` | +| 0x834 | `gpio_3_ios_2` | 0, `pmod1_3` | +| 0x835 | `gpio_3_ios_3` | 0, `pmod1_4` | +| 0x836 | `gpio_3_ios_4` | 0, `pmod1_7` | +| 0x837 | `gpio_3_ios_5` | 0, `pmod1_8` | +| 0x838 | `gpio_3_ios_6` | 0, `pmod1_9` | +| 0x839 | `gpio_3_ios_7` | 0, `pmod1_10` | +| 0x83a | `gpio_4_ios_0` | 0, `pmodc_1` | +| 0x83b | `gpio_4_ios_1` | 0, `pmodc_2` | +| 0x83c | `gpio_4_ios_2` | 0, `pmodc_3` | +| 0x83d | `gpio_4_ios_3` | 0, `pmodc_4` | +| 0x83e | `gpio_4_ios_4` | 0, `pmodc_5` | +| 0x83f | `gpio_4_ios_5` | 0, `pmodc_6` | +| 0x840 | `uart_0_rx` | 1, `ser0_rx` | +| 0x841 | `uart_1_rx` | 1, `ser1_rx`, `rph_rxd0`, `ah_tmpio0`, `mb8`, `pmod0_3` | +| 0x842 | `uart_2_rx` | 1, `ser1_rx`, `rs232_rx`, `rs485_rx`, `pmod1_3` | +| 0x843 | `spi_0_cipo` | 0, `appspi_d1`, `microsd_dat0` | +| 0x844 | `spi_1_cipo` | 0, `rph_g9`, `ah_tmpio12`, `pmod0_3` | +| 0x845 | `spi_2_cipo` | 0, `rph_g19`, `mb3`, `pmod1_3` | ## Regeneration diff --git a/sw/cheri/checks/pinmux_all_blocks_check.cc b/sw/cheri/checks/pinmux_all_blocks_check.cc index a6dcedddf..4c5b90aa4 100644 --- a/sw/cheri/checks/pinmux_all_blocks_check.cc +++ b/sw/cheri/checks/pinmux_all_blocks_check.cc @@ -50,10 +50,7 @@ using namespace CHERI; SonataGpioFull gpio_full = get_full_gpio_ptrs(root); - Capability pinmux = root.cast(); - pinmux.address() = PINMUX_ADDRESS; - pinmux.bounds() = PINMUX_BOUNDS; - SonataPinmux Pinmux = SonataPinmux(pinmux); + PinmuxPtrs pinmux = std::pair{pin_sinks_ptr(root), block_sinks_ptr(root)}; // Initialise Pseudo-Random Number Generation for use in Pinmux UART testing ds::xoroshiro::P32R8 prng; @@ -64,33 +61,33 @@ using namespace CHERI; // initializers, as that requires `memcpy` to exist which we do not have. // Likewise, arrays with multiple pins/inputs must be individually set, or // we will get errors with `memcpy`. - OutputPinAssignment pmod_test_gpio_on_pins[] = {{SonataPinmux::OutputPin::pmod0_2, 1}}; - BlockInputAssignment pmod_test_gpio_on_inputs[] = {{SonataPinmux::BlockInput::gpio_2_ios_2, 1}}; - OutputPinAssignment pmod_test_gpio_off_pins[] = {{SonataPinmux::OutputPin::pmod0_2, 0}}; - BlockInputAssignment pmod_test_gpio_off_inputs[] = {{SonataPinmux::BlockInput::gpio_2_ios_2, 0}}; + OutputPinAssignment pmod_test_gpio_on_pins[] = {{SonataPinmux::PinSink::pmod0_2, 1}}; + BlockInputAssignment pmod_test_gpio_on_inputs[] = {{SonataPinmux::BlockSink::gpio_2_ios_2, 1}}; + OutputPinAssignment pmod_test_gpio_off_pins[] = {{SonataPinmux::PinSink::pmod0_2, 0}}; + BlockInputAssignment pmod_test_gpio_off_inputs[] = {{SonataPinmux::BlockSink::gpio_2_ios_2, 0}}; - OutputPinAssignment pmod_test_uart_on_pins[] = {{SonataPinmux::OutputPin::pmod0_2, 4}}; - BlockInputAssignment pmod_test_uart_on_inputs[] = {{SonataPinmux::BlockInput::uart_1_rx, 5}}; - OutputPinAssignment pmod_test_uart_off_pins[] = {{SonataPinmux::OutputPin::pmod0_2, 0}}; - BlockInputAssignment pmod_test_uart_off_inputs[] = {{SonataPinmux::BlockInput::uart_1_rx, 0}}; + OutputPinAssignment pmod_test_uart_on_pins[] = {{SonataPinmux::PinSink::pmod0_2, 4}}; + BlockInputAssignment pmod_test_uart_on_inputs[] = {{SonataPinmux::BlockSink::uart_1_rx, 5}}; + OutputPinAssignment pmod_test_uart_off_pins[] = {{SonataPinmux::PinSink::pmod0_2, 0}}; + BlockInputAssignment pmod_test_uart_off_inputs[] = {{SonataPinmux::BlockSink::uart_1_rx, 0}}; OutputPinAssignment pmod_test_i2c_on_pins[2]; - pmod_test_i2c_on_pins[0] = {SonataPinmux::OutputPin::pmod0_3, 2}; // Mux to I2C SDA - pmod_test_i2c_on_pins[1] = {SonataPinmux::OutputPin::pmod0_4, 3}; // Mux to I2C SCL + pmod_test_i2c_on_pins[0] = {SonataPinmux::PinSink::pmod0_3, 2}; // Mux to I2C SDA + pmod_test_i2c_on_pins[1] = {SonataPinmux::PinSink::pmod0_4, 3}; // Mux to I2C SCL OutputPinAssignment pmod_test_i2c_off_pins[2]; - pmod_test_i2c_off_pins[0] = {SonataPinmux::OutputPin::pmod0_3, 0}; - pmod_test_i2c_off_pins[1] = {SonataPinmux::OutputPin::pmod0_4, 0}; + pmod_test_i2c_off_pins[0] = {SonataPinmux::PinSink::pmod0_3, 0}; + pmod_test_i2c_off_pins[1] = {SonataPinmux::PinSink::pmod0_4, 0}; OutputPinAssignment pmod_test_spi_on_pins[3]; - pmod_test_spi_on_pins[0] = {SonataPinmux::OutputPin::pmod0_1, 2}; // Mux to SPI CS - pmod_test_spi_on_pins[1] = {SonataPinmux::OutputPin::pmod0_2, 2}; // Mux to SPI COPI - pmod_test_spi_on_pins[2] = {SonataPinmux::OutputPin::pmod0_4, 2}; // Mux to SPI SCK - BlockInputAssignment pmod_test_spi_on_inputs[] = {{SonataPinmux::BlockInput::spi_1_cipo, 3}}; + pmod_test_spi_on_pins[0] = {SonataPinmux::PinSink::pmod0_1, 2}; // Mux to SPI CS + pmod_test_spi_on_pins[1] = {SonataPinmux::PinSink::pmod0_2, 2}; // Mux to SPI COPI + pmod_test_spi_on_pins[2] = {SonataPinmux::PinSink::pmod0_4, 2}; // Mux to SPI SCK + BlockInputAssignment pmod_test_spi_on_inputs[] = {{SonataPinmux::BlockSink::spi_1_cipo, 3}}; OutputPinAssignment pmod_test_spi_off_pins[3]; - pmod_test_spi_off_pins[0] = {SonataPinmux::OutputPin::pmod0_1, 0}; - pmod_test_spi_off_pins[1] = {SonataPinmux::OutputPin::pmod0_2, 0}; - pmod_test_spi_off_pins[2] = {SonataPinmux::OutputPin::pmod0_4, 0}; - BlockInputAssignment pmod_test_spi_off_inputs[] = {{SonataPinmux::BlockInput::spi_1_cipo, 0}}; + pmod_test_spi_off_pins[0] = {SonataPinmux::PinSink::pmod0_1, 0}; + pmod_test_spi_off_pins[1] = {SonataPinmux::PinSink::pmod0_2, 0}; + pmod_test_spi_off_pins[2] = {SonataPinmux::PinSink::pmod0_4, 0}; + BlockInputAssignment pmod_test_spi_off_inputs[] = {{SonataPinmux::BlockSink::spi_1_cipo, 0}}; // The pinmux testplan to execute. This testplan runs through testing GPIO, UART, I2C and SPI // all on the same PMOD pins, with users manually changing out the connected devices between @@ -213,7 +210,7 @@ using namespace CHERI; // Execute the pinmux testplan const uint8_t NumTests = ARRAYSIZE(pinmux_testplan); - execute_testplan(pinmux_testplan, NumTests, log, prng, &gpio_full, uarts, spis, i2cs, &Pinmux); + execute_testplan(pinmux_testplan, NumTests, log, prng, &gpio_full, uarts, spis, i2cs, pinmux); // Infinite loop to stop execution returning while (true) { diff --git a/sw/cheri/checks/pinmux_check.cc b/sw/cheri/checks/pinmux_check.cc index 9dd5ac36c..50de0346b 100644 --- a/sw/cheri/checks/pinmux_check.cc +++ b/sw/cheri/checks/pinmux_check.cc @@ -11,22 +11,18 @@ #include "../../common/defs.h" #include "../common/uart-utils.hh" #include "../common/platform-pinmux.hh" +#include "../common/sonata-devices.hh" #include #define LOG(...) write_str(uart, __VA_ARGS__) using namespace CHERI; -#define PINMUX_SER0_TX_DISABLED (0) -#define PINMUX_SER0_TX_UART0_TX (1) - /** * Blocks until the UART transmit FIFO is empty. */ void block_until_uart_tx_done(Capability uart) { - while (uart->transmit_fifo_level() > 0) { - asm volatile(""); - } + while (!(uart->status & uart->StatusTransmitIdle)); } /** @@ -38,16 +34,10 @@ void block_until_uart_tx_done(Capability uart) { [[noreturn]] extern "C" void entry_point(void *rwRoot) { Capability root{rwRoot}; - Capability uart = root.cast(); - uart.address() = UART_ADDRESS; - uart.bounds() = UART_BOUNDS; + UartPtr uart = uart_ptr(root); uart->init(BAUD_RATE); - Capability pinmux = root.cast(); - pinmux.address() = PINMUX_ADDRESS; - pinmux.bounds() = PINMUX_BOUNDS; - - SonataPinmux Pinmux = SonataPinmux(pinmux); + SonataPinmux::Sink ser0_tx = pin_sinks_ptr(root)->get(SonataPinmux::PinSink::ser0_tx); LOG("Starting check.\r\n"); @@ -55,12 +45,13 @@ void block_until_uart_tx_done(Capability uart) { block_until_uart_tx_done(uart); // Pinmux Serial 0 TX (used by console UART) to OFF. - Pinmux.output_pin_select(SonataPinmux::OutputPin::ser0_tx, PINMUX_SER0_TX_DISABLED); + + ser0_tx.disable(); LOG("You should NOT see this message, as we just used pinmux to disable UART0 output.\r\n"); block_until_uart_tx_done(uart); // Pinmux Serial 0 TX (used by console UART) to UART0_TX. - Pinmux.output_pin_select(SonataPinmux::OutputPin::ser0_tx, PINMUX_SER0_TX_UART0_TX); + ser0_tx.default_selection(); LOG("You should see this message, as UART0 has just been re-enabled.\r\n"); LOG("Check completed.\r\n"); diff --git a/sw/cheri/checks/pinmux_checker.cc b/sw/cheri/checks/pinmux_checker.cc index 20aae1cae..33231fe8e 100644 --- a/sw/cheri/checks/pinmux_checker.cc +++ b/sw/cheri/checks/pinmux_checker.cc @@ -151,7 +151,7 @@ static inline bool joystick_moved(SonataGpioFull *gpio) { * otherwise. */ bool execute_test(const Test &test, uint32_t test_num, Log &log, ds::xoroshiro::P32R8 &prng, SonataGpioFull *gpio, - UartPtr uarts[2], SpiPtr spis[3], I2cPtr i2cs[2], SonataPinmux *pinmux) { + UartPtr uarts[2], SpiPtr spis[3], I2cPtr i2cs[2], PinmuxPtrs pinmux) { // If manual intervention is required, print out the test instruction and wait // for the user to press the joystick to signal that they are ready. if (test.manual_required) { @@ -172,7 +172,7 @@ bool execute_test(const Test &test, uint32_t test_num, Log &log, ds::xoroshiro:: // Configure the output pins and block inputs via pinmux for (uint32_t i = 0; i < test.num_output_pins; i++) { auto pin_assign = test.output_pins[i]; - if (!pinmux->output_pin_select(pin_assign.pin, pin_assign.select)) { + if (!std::get(pinmux)->get(pin_assign.pin).select(pin_assign.select)) { log.println(""); log.print("{}Error: invalid pinmux output pin selection.", prefix); return false; @@ -180,7 +180,7 @@ bool execute_test(const Test &test, uint32_t test_num, Log &log, ds::xoroshiro:: } for (uint32_t i = 0; i < test.num_block_inputs; i++) { auto block_assign = test.block_inputs[i]; - if (!pinmux->block_input_select(block_assign.input, block_assign.select)) { + if (!std::get(pinmux)->get(block_assign.input).select(block_assign.select)) { log.println(""); log.print("{}Error: invalid pinmux block input selection.", prefix); return false; @@ -264,7 +264,7 @@ bool ask_retry_last_test(Log &log, SonataGpioFull *gpio) { * otherwise. Will return true even if there were retries. */ bool execute_testplan(Test *testplan, uint8_t NumTests, Log &log, ds::xoroshiro::P32R8 &prng, SonataGpioFull *gpio, - UartPtr uarts[2], SpiPtr spis[3], I2cPtr i2cs[2], SonataPinmux *pinmux) { + UartPtr uarts[2], SpiPtr spis[3], I2cPtr i2cs[2], PinmuxPtrs pinmux) { log.println(""); log.println("{}Starting check.", prefix); log.println(""); diff --git a/sw/cheri/checks/pinmux_checker.hh b/sw/cheri/checks/pinmux_checker.hh index cb78b94d8..b2c14eea8 100644 --- a/sw/cheri/checks/pinmux_checker.hh +++ b/sw/cheri/checks/pinmux_checker.hh @@ -79,13 +79,13 @@ struct SpiTest { // An output pin assignment to be made via Pinmux for a test struct OutputPinAssignment { - SonataPinmux::OutputPin pin; + SonataPinmux::PinSink pin; uint8_t select; }; // A block input assignment to be made via Pinmux for a test struct BlockInputAssignment { - SonataPinmux::BlockInput input; + SonataPinmux::BlockSink input; uint8_t select; }; @@ -126,4 +126,4 @@ struct Test { }; bool execute_testplan(Test *testplan, uint8_t NumTests, Log &log, ds::xoroshiro::P32R8 &prng, SonataGpioFull *gpio, - UartPtr uarts[4], SpiPtr spis[3], I2cPtr i2cs[2], SonataPinmux *pinmux); + UartPtr uarts[4], SpiPtr spis[3], I2cPtr i2cs[2], PinmuxPtrs pinmux); diff --git a/sw/cheri/checks/rs485_check.cc b/sw/cheri/checks/rs485_check.cc index caaa38c0e..3a69dbcaf 100644 --- a/sw/cheri/checks/rs485_check.cc +++ b/sw/cheri/checks/rs485_check.cc @@ -12,6 +12,7 @@ #include "../common/uart-utils.hh" #include "../common/platform-pinmux.hh" #include "../common/timer-utils.hh" +#include "../common/sonata-devices.hh" #include #define RS485_UART 2 @@ -21,18 +22,10 @@ using namespace CHERI; [[noreturn]] extern "C" void entry_point(void *rwRoot) { Capability root{rwRoot}; - Capability pinmux = root.cast(); - pinmux.address() = PINMUX_ADDRESS; - pinmux.bounds() = PINMUX_BOUNDS; + pin_sinks_ptr(root)->get(SonataPinmux::PinSink::rs485_tx).select(1); + block_sinks_ptr(root)->get(SonataPinmux::BlockSink::uart_2_rx).select(3); - SonataPinmux Pinmux = SonataPinmux(pinmux); - - Pinmux.output_pin_select(SonataPinmux::OutputPin::rs485_tx, 1); - Pinmux.block_input_select(SonataPinmux::BlockInput::uart_2_rx, 3); - - Capability uart = root.cast(); - uart.address() = UART_ADDRESS; - uart.bounds() = UART_BOUNDS; + UartPtr uart = uart_ptr(root, 0); uart->init(BAUD_RATE); Capability rs485_uart = root.cast(); diff --git a/sw/cheri/checks/rs485_spam_check.cc b/sw/cheri/checks/rs485_spam_check.cc index 11338fb05..5445f751c 100644 --- a/sw/cheri/checks/rs485_spam_check.cc +++ b/sw/cheri/checks/rs485_spam_check.cc @@ -12,6 +12,7 @@ #include "../common/uart-utils.hh" #include "../common/platform-pinmux.hh" #include "../common/timer-utils.hh" +#include "../common/sonata-devices.hh" #include #define RS485_UART 2 @@ -22,18 +23,10 @@ using namespace CHERI; [[noreturn]] extern "C" void entry_point(void *rwRoot) { Capability root{rwRoot}; - Capability pinmux = root.cast(); - pinmux.address() = PINMUX_ADDRESS; - pinmux.bounds() = PINMUX_BOUNDS; + pin_sinks_ptr(root)->get(SonataPinmux::PinSink::rs485_tx).select(1); + block_sinks_ptr(root)->get(SonataPinmux::BlockSink::uart_2_rx).select(3); - SonataPinmux Pinmux = SonataPinmux(pinmux); - - Pinmux.output_pin_select(SonataPinmux::OutputPin::rs485_tx, 1); - Pinmux.block_input_select(SonataPinmux::BlockInput::uart_2_rx, 3); - - Capability uart = root.cast(); - uart.address() = UART_ADDRESS; - uart.bounds() = UART_BOUNDS; + UartPtr uart = uart_ptr(root, 0); uart->init(BAUD_RATE); Capability rs485_uart = root.cast(); diff --git a/sw/cheri/common/platform-pinmux.hh b/sw/cheri/common/platform-pinmux.hh index 9a7c77a17..b931877c0 100644 --- a/sw/cheri/common/platform-pinmux.hh +++ b/sw/cheri/common/platform-pinmux.hh @@ -1,368 +1,376 @@ -/** - * Copyright lowRISC contributors. - * Licensed under the Apache License, Version 2.0, see LICENSE for details. - * SPDX-License-Identifier: Apache-2.0 - */ +// SPDX-FileCopyrightText: lowRISC contributors +// SPDX-License-Identifier: Apache-2.0 #pragma once #include #include #include +#include -/** - * A driver for Sonata's Pin Multiplexer (Pinmux). - * - * This driver can be used to select which block output is placed on a given - * output pin, and to select which input pin is provided to a given block - * input. Sonata's pinmux only allows certain selections per output pin / block - * input, which this driver describes. - * - * Rendered documentation is served from: - * https://lowrisc.github.io/sonata-system/doc/ip/pinmux.html - */ -class SonataPinmux : private utils::NoCopyNoMove { - /** - * Flag to set when debugging the driver for UART log messages. - */ - static constexpr bool DebugDriver = false; +namespace SonataPinmux { +/// The number of pin sinks (pin outputs) +static constexpr size_t NumPinSinks = 85; - /** - * Helper for conditional debug logs and assertions. - */ - using Debug = ConditionalDebug; +/// The number of block sinks (block inputs) +static constexpr size_t NumBlockSinks = 70; - /** - * A pointer/capability to the Pin Multiplexer's registers, where - * each sequential byte potentially corresponds to some mapped pinmux - * selector used to select the pin configuration. - */ - volatile uint8_t *registers; +/// Flag to set when debugging the driver for UART log messages. +static constexpr bool DebugDriver = false; - public: - /** - * The Output Pins defined for the Sonata board. These output pins can be - * multiplexed, meaning that they can be changed to output the outputs - * of different blocks (or disabled). The block outputs that can be - * selected are limited, and vary on a per-pin basis. - * - * Documentation sources: - * https://lowrisc.github.io/sonata-system/doc/ip/pinmux.html - * https://github.com/lowRISC/sonata-system/blob/4b72d8c07c727846c6ccb27754352388f3b2ac9a/data/pins_sonata.xdc - * https://github.com/newaetech/sonata-pcb/blob/649b11c2fb758f798966605a07a8b6b68dd434e9/sonata-schematics-r09.pdf - */ - enum class OutputPin : uint16_t { - ser0_tx = 0x000, - ser1_tx = 0x001, - rs232_tx = 0x002, - rs485_tx = 0x003, - scl0 = 0x004, - sda0 = 0x005, - scl1 = 0x006, - sda1 = 0x007, - rph_g0 = 0x008, - rph_g1 = 0x009, - rph_g2_sda = 0x00a, - rph_g3_scl = 0x00b, - rph_g4 = 0x00c, - rph_g5 = 0x00d, - rph_g6 = 0x00e, - rph_g7 = 0x00f, - rph_g8 = 0x010, - rph_g9 = 0x011, - rph_g10 = 0x012, - rph_g11 = 0x013, - rph_g12 = 0x014, - rph_g13 = 0x015, - rph_txd0 = 0x016, - rph_rxd0 = 0x017, - rph_g16 = 0x018, - rph_g17 = 0x019, - rph_g18 = 0x01a, - rph_g19 = 0x01b, - rph_g20 = 0x01c, - rph_g21 = 0x01d, - rph_g22 = 0x01e, - rph_g23 = 0x01f, - rph_g24 = 0x020, - rph_g25 = 0x021, - rph_g26 = 0x022, - rph_g27 = 0x023, - ah_tmpio0 = 0x024, - ah_tmpio1 = 0x025, - ah_tmpio2 = 0x026, - ah_tmpio3 = 0x027, - ah_tmpio4 = 0x028, - ah_tmpio5 = 0x029, - ah_tmpio6 = 0x02a, - ah_tmpio7 = 0x02b, - ah_tmpio8 = 0x02c, - ah_tmpio9 = 0x02d, - ah_tmpio10 = 0x02e, - ah_tmpio11 = 0x02f, - ah_tmpio12 = 0x030, - ah_tmpio13 = 0x031, - mb1 = 0x032, - mb2 = 0x033, - mb4 = 0x034, - mb5 = 0x035, - mb6 = 0x036, - mb7 = 0x037, - mb10 = 0x038, - pmod0_1 = 0x039, - pmod0_2 = 0x03a, - pmod0_3 = 0x03b, - pmod0_4 = 0x03c, - pmod0_7 = 0x03d, - pmod0_8 = 0x03e, - pmod0_9 = 0x03f, - pmod0_10 = 0x040, - pmod1_1 = 0x041, - pmod1_2 = 0x042, - pmod1_3 = 0x043, - pmod1_4 = 0x044, - pmod1_7 = 0x045, - pmod1_8 = 0x046, - pmod1_9 = 0x047, - pmod1_10 = 0x048, - pmodc_1 = 0x049, - pmodc_2 = 0x04a, - pmodc_3 = 0x04b, - pmodc_4 = 0x04c, - pmodc_5 = 0x04d, - pmodc_6 = 0x04e, - appspi_d0 = 0x04f, - appspi_clk = 0x050, - appspi_cs = 0x051, - microsd_cmd = 0x052, - microsd_clk = 0x053, - microsd_dat3 = 0x054, - }; +/// Helper for conditional debug logs and assertions. +using Debug = ConditionalDebug; - /** - * The Block Inputs defined for the Sonata board. These block inputs can - * be multiplexed, meaning that they can be changed to take the input of - * different pins (or be disabled). The pin inputs that can be selected - * are limited, and vary on a per-block-input basis. - * - * For reference: - * gpio_0 = Raspberry Pi - * gpio_1 = ArduinoShield - * gpio_2 = Pmod - * - * Documentation source: - * https://lowrisc.github.io/sonata-system/doc/ip/pinmux.html - * */ - enum class BlockInput : uint16_t { - gpio_0_ios_0 = 0x800, - gpio_0_ios_1 = 0x801, - gpio_0_ios_2 = 0x802, - gpio_0_ios_3 = 0x803, - gpio_0_ios_4 = 0x804, - gpio_0_ios_5 = 0x805, - gpio_0_ios_6 = 0x806, - gpio_0_ios_7 = 0x807, - gpio_0_ios_8 = 0x808, - gpio_0_ios_9 = 0x809, - gpio_0_ios_10 = 0x80a, - gpio_0_ios_11 = 0x80b, - gpio_0_ios_12 = 0x80c, - gpio_0_ios_13 = 0x80d, - gpio_0_ios_14 = 0x80e, - gpio_0_ios_15 = 0x80f, - gpio_0_ios_16 = 0x810, - gpio_0_ios_17 = 0x811, - gpio_0_ios_18 = 0x812, - gpio_0_ios_19 = 0x813, - gpio_0_ios_20 = 0x814, - gpio_0_ios_21 = 0x815, - gpio_0_ios_22 = 0x816, - gpio_0_ios_23 = 0x817, - gpio_0_ios_24 = 0x818, - gpio_0_ios_25 = 0x819, - gpio_0_ios_26 = 0x81a, - gpio_0_ios_27 = 0x81b, - gpio_1_ios_0 = 0x81c, - gpio_1_ios_1 = 0x81d, - gpio_1_ios_2 = 0x81e, - gpio_1_ios_3 = 0x81f, - gpio_1_ios_4 = 0x820, - gpio_1_ios_5 = 0x821, - gpio_1_ios_6 = 0x822, - gpio_1_ios_7 = 0x823, - gpio_1_ios_8 = 0x824, - gpio_1_ios_9 = 0x825, - gpio_1_ios_10 = 0x826, - gpio_1_ios_11 = 0x827, - gpio_1_ios_12 = 0x828, - gpio_1_ios_13 = 0x829, - gpio_2_ios_0 = 0x82a, - gpio_2_ios_1 = 0x82b, - gpio_2_ios_2 = 0x82c, - gpio_2_ios_3 = 0x82d, - gpio_2_ios_4 = 0x82e, - gpio_2_ios_5 = 0x82f, - gpio_2_ios_6 = 0x830, - gpio_2_ios_7 = 0x831, - gpio_3_ios_0 = 0x832, - gpio_3_ios_1 = 0x833, - gpio_3_ios_2 = 0x834, - gpio_3_ios_3 = 0x835, - gpio_3_ios_4 = 0x836, - gpio_3_ios_5 = 0x837, - gpio_3_ios_6 = 0x838, - gpio_3_ios_7 = 0x839, - gpio_4_ios_0 = 0x83a, - gpio_4_ios_1 = 0x83b, - gpio_4_ios_2 = 0x83c, - gpio_4_ios_3 = 0x83d, - gpio_4_ios_4 = 0x83e, - gpio_4_ios_5 = 0x83f, - uart_0_rx = 0x840, - uart_1_rx = 0x841, - uart_2_rx = 0x842, - spi_0_cipo = 0x843, - spi_1_cipo = 0x844, - spi_2_cipo = 0x845, - }; +/// The disable bit that disables a sink +constexpr uint8_t SourceDisabled = 0; - /** - * A helper function that returns the number of block outputs that can be - * selected from in the pin multiplexer for a given output pin. This will - * always be at least 2, as option 0 represents 'OFF' i.e. no connection, - * and option 1 represents the default connection. - * - * @param output_pin The output pin to query - * @returns The number of selections available for that output pin - * - * The meanings of these selections can be found in the documentation: - * https://lowrisc.github.io/sonata-system/doc/ip/pinmux.html - */ - static constexpr uint8_t output_pin_options(OutputPin output_pin) { - switch (output_pin) { - case OutputPin::pmod0_2: - case OutputPin::pmod1_2: - return 5; - case OutputPin::rph_g18: - case OutputPin::rph_g20: - case OutputPin::rph_g21: - case OutputPin::ah_tmpio10: - case OutputPin::ah_tmpio11: - case OutputPin::pmod0_4: - case OutputPin::pmod1_4: - return 4; - case OutputPin::ser1_tx: - case OutputPin::rph_g0: - case OutputPin::rph_g1: - case OutputPin::rph_g2_sda: - case OutputPin::rph_g3_scl: - case OutputPin::rph_g7: - case OutputPin::rph_g8: - case OutputPin::rph_g10: - case OutputPin::rph_g11: - case OutputPin::rph_g12: - case OutputPin::rph_g13: - case OutputPin::rph_txd0: - case OutputPin::rph_g16: - case OutputPin::rph_g17: - case OutputPin::rph_g19: - case OutputPin::ah_tmpio1: - case OutputPin::ah_tmpio3: - case OutputPin::ah_tmpio5: - case OutputPin::ah_tmpio6: - case OutputPin::ah_tmpio9: - case OutputPin::ah_tmpio13: - case OutputPin::pmod0_1: - case OutputPin::pmod0_3: - case OutputPin::pmod0_8: - case OutputPin::pmod0_9: - case OutputPin::pmod0_10: - case OutputPin::pmod1_1: - case OutputPin::pmod1_3: - case OutputPin::pmod1_8: - case OutputPin::pmod1_9: - case OutputPin::pmod1_10: - return 3; - default: - return 2; - } - } +/// The bit that resets a sink to it's default value +constexpr uint8_t SourceDefault = 1; - /** - * A helper function that returns the number of input pins that can be - * selected from in the pin multiplexer for a given block input. This will - * always be at least 2, as option 0 represents 'OFF' i.e. no connection, - * and option 1 represents the default connection. - * - * @param block_input The block input to query. - * @returns The number of selections available for that block input. - * - * The meanings of these selections can be found in the documentation: - * https://lowrisc.github.io/sonata-system/doc/ip/pinmux.html - */ - static constexpr uint8_t block_input_options(BlockInput block_input) { - switch (block_input) { - case BlockInput::uart_1_rx: - return 6; - case BlockInput::uart_2_rx: - return 5; - case BlockInput::spi_1_cipo: - case BlockInput::spi_2_cipo: - return 4; - case BlockInput::spi_0_cipo: - return 3; - default: - return 2; - } +/** + * Each pin sink is configured by an 8-bit register. This enum maps pin sink + * names to the offset of their configuration registers. The offsets are relative + * to the first pin sink register. + * + * Documentation sources: + * 1. https://lowrisc.github.io/sonata-system/doc/ip/pinmux/ + * 2. https://github.com/lowRISC/sonata-system/blob/v1.0/data/pins_sonata.xdc + * 3. https://github.com/newaetech/sonata-pcb/blob/649b11c2fb758f798966605a07a8b6b68dd434e9/sonata-schematics-r09.pdf + */ +enum class PinSink : uint16_t { + ser0_tx = 0x000, + ser1_tx = 0x001, + rs232_tx = 0x002, + rs485_tx = 0x003, + scl0 = 0x004, + sda0 = 0x005, + scl1 = 0x006, + sda1 = 0x007, + rph_g0 = 0x008, + rph_g1 = 0x009, + rph_g2_sda = 0x00a, + rph_g3_scl = 0x00b, + rph_g4 = 0x00c, + rph_g5 = 0x00d, + rph_g6 = 0x00e, + rph_g7 = 0x00f, + rph_g8 = 0x010, + rph_g9 = 0x011, + rph_g10 = 0x012, + rph_g11 = 0x013, + rph_g12 = 0x014, + rph_g13 = 0x015, + rph_txd0 = 0x016, + rph_rxd0 = 0x017, + rph_g16 = 0x018, + rph_g17 = 0x019, + rph_g18 = 0x01a, + rph_g19 = 0x01b, + rph_g20 = 0x01c, + rph_g21 = 0x01d, + rph_g22 = 0x01e, + rph_g23 = 0x01f, + rph_g24 = 0x020, + rph_g25 = 0x021, + rph_g26 = 0x022, + rph_g27 = 0x023, + ah_tmpio0 = 0x024, + ah_tmpio1 = 0x025, + ah_tmpio2 = 0x026, + ah_tmpio3 = 0x027, + ah_tmpio4 = 0x028, + ah_tmpio5 = 0x029, + ah_tmpio6 = 0x02a, + ah_tmpio7 = 0x02b, + ah_tmpio8 = 0x02c, + ah_tmpio9 = 0x02d, + ah_tmpio10 = 0x02e, + ah_tmpio11 = 0x02f, + ah_tmpio12 = 0x030, + ah_tmpio13 = 0x031, + mb1 = 0x032, + mb2 = 0x033, + mb4 = 0x034, + mb5 = 0x035, + mb6 = 0x036, + mb7 = 0x037, + mb10 = 0x038, + pmod0_1 = 0x039, + pmod0_2 = 0x03a, + pmod0_3 = 0x03b, + pmod0_4 = 0x03c, + pmod0_7 = 0x03d, + pmod0_8 = 0x03e, + pmod0_9 = 0x03f, + pmod0_10 = 0x040, + pmod1_1 = 0x041, + pmod1_2 = 0x042, + pmod1_3 = 0x043, + pmod1_4 = 0x044, + pmod1_7 = 0x045, + pmod1_8 = 0x046, + pmod1_9 = 0x047, + pmod1_10 = 0x048, + pmodc_1 = 0x049, + pmodc_2 = 0x04a, + pmodc_3 = 0x04b, + pmodc_4 = 0x04c, + pmodc_5 = 0x04d, + pmodc_6 = 0x04e, + appspi_d0 = 0x04f, + appspi_clk = 0x050, + appspi_cs = 0x051, + microsd_cmd = 0x052, + microsd_clk = 0x053, + microsd_dat3 = 0x054, +}; + +/** + * Each block sink is configured by an 8-bit register. This enum maps block sink + * names to the offset of their configuration registers. The offsets are relative + * to the first block sink register. + * + * For GPIO block reference: + * gpio_0 = Raspberry Pi Header Pins + * gpio_1 = Arduino Shield Header Pins + * gpio_2 = Pmod0 Pins + * gpio_3 = Pmod1 Pins + * gpio_4 = PmodC Pins + * + * Documentation source: + * https://lowrisc.github.io/sonata-system/doc/ip/pinmux/ + */ +enum class BlockSink : uint16_t { + gpio_0_ios_0 = 0x000, + gpio_0_ios_1 = 0x001, + gpio_0_ios_2 = 0x002, + gpio_0_ios_3 = 0x003, + gpio_0_ios_4 = 0x004, + gpio_0_ios_5 = 0x005, + gpio_0_ios_6 = 0x006, + gpio_0_ios_7 = 0x007, + gpio_0_ios_8 = 0x008, + gpio_0_ios_9 = 0x009, + gpio_0_ios_10 = 0x00a, + gpio_0_ios_11 = 0x00b, + gpio_0_ios_12 = 0x00c, + gpio_0_ios_13 = 0x00d, + gpio_0_ios_14 = 0x00e, + gpio_0_ios_15 = 0x00f, + gpio_0_ios_16 = 0x010, + gpio_0_ios_17 = 0x011, + gpio_0_ios_18 = 0x012, + gpio_0_ios_19 = 0x013, + gpio_0_ios_20 = 0x014, + gpio_0_ios_21 = 0x015, + gpio_0_ios_22 = 0x016, + gpio_0_ios_23 = 0x017, + gpio_0_ios_24 = 0x018, + gpio_0_ios_25 = 0x019, + gpio_0_ios_26 = 0x01a, + gpio_0_ios_27 = 0x01b, + gpio_1_ios_0 = 0x01c, + gpio_1_ios_1 = 0x01d, + gpio_1_ios_2 = 0x01e, + gpio_1_ios_3 = 0x01f, + gpio_1_ios_4 = 0x020, + gpio_1_ios_5 = 0x021, + gpio_1_ios_6 = 0x022, + gpio_1_ios_7 = 0x023, + gpio_1_ios_8 = 0x024, + gpio_1_ios_9 = 0x025, + gpio_1_ios_10 = 0x026, + gpio_1_ios_11 = 0x027, + gpio_1_ios_12 = 0x028, + gpio_1_ios_13 = 0x029, + gpio_2_ios_0 = 0x02a, + gpio_2_ios_1 = 0x02b, + gpio_2_ios_2 = 0x02c, + gpio_2_ios_3 = 0x02d, + gpio_2_ios_4 = 0x02e, + gpio_2_ios_5 = 0x02f, + gpio_2_ios_6 = 0x030, + gpio_2_ios_7 = 0x031, + gpio_3_ios_0 = 0x032, + gpio_3_ios_1 = 0x033, + gpio_3_ios_2 = 0x034, + gpio_3_ios_3 = 0x035, + gpio_3_ios_4 = 0x036, + gpio_3_ios_5 = 0x037, + gpio_3_ios_6 = 0x038, + gpio_3_ios_7 = 0x039, + gpio_4_ios_0 = 0x03a, + gpio_4_ios_1 = 0x03b, + gpio_4_ios_2 = 0x03c, + gpio_4_ios_3 = 0x03d, + gpio_4_ios_4 = 0x03e, + gpio_4_ios_5 = 0x03f, + uart_0_rx = 0x040, + uart_1_rx = 0x041, + uart_2_rx = 0x042, + spi_0_cipo = 0x043, + spi_1_cipo = 0x044, + spi_2_cipo = 0x045, +}; + +/** + * Returns the number of sources available for a pin sink (output pin). + * + * @param pin_sink The pin sink to query. + * @returns The number of sources available for the given sink. + */ +static constexpr uint8_t sources_number(PinSink pin_sink) { + switch (pin_sink) { + case PinSink::pmod0_2: + case PinSink::pmod1_2: + return 5; + case PinSink::rph_g18: + case PinSink::rph_g20: + case PinSink::rph_g21: + case PinSink::ah_tmpio10: + case PinSink::ah_tmpio11: + case PinSink::pmod0_4: + case PinSink::pmod1_4: + return 4; + case PinSink::ser1_tx: + case PinSink::rph_g0: + case PinSink::rph_g1: + case PinSink::rph_g2_sda: + case PinSink::rph_g3_scl: + case PinSink::rph_g7: + case PinSink::rph_g8: + case PinSink::rph_g10: + case PinSink::rph_g11: + case PinSink::rph_g12: + case PinSink::rph_g13: + case PinSink::rph_txd0: + case PinSink::rph_g16: + case PinSink::rph_g17: + case PinSink::rph_g19: + case PinSink::ah_tmpio1: + case PinSink::ah_tmpio3: + case PinSink::ah_tmpio5: + case PinSink::ah_tmpio6: + case PinSink::ah_tmpio9: + case PinSink::ah_tmpio13: + case PinSink::pmod0_1: + case PinSink::pmod0_3: + case PinSink::pmod0_8: + case PinSink::pmod0_9: + case PinSink::pmod0_10: + case PinSink::pmod1_1: + case PinSink::pmod1_3: + case PinSink::pmod1_8: + case PinSink::pmod1_9: + case PinSink::pmod1_10: + return 3; + default: + return 2; } +} - /** - * For a given output pin, selects a given block output to use for that pin - * via the pin multiplexer. - * - * @param output_pin The output pin to pinmux. - * @param option The option to select for that pin. This value should be - * less than the value returned by `output_pin_options` for the given pin. - * - * The meanings of these selections can be found in the documentation: - * https://lowrisc.github.io/sonata-system/doc/ip/pinmux.html - */ - bool output_pin_select(OutputPin output_pin, uint8_t option) { - if (option >= output_pin_options(output_pin)) { - Debug::log("Selected option is not valid for this pin."); - return false; - } - uint16_t registerOffset = static_cast(output_pin); - registers[registerOffset] = (1 << option); - return true; +/** + * Returns the number of sources available for a block sink (block input). + * + * @param block_sink The block sink to query. + * @returns The number of sources available for the given sink. + */ +static constexpr uint8_t sources_number(BlockSink block_sink) { + switch (block_sink) { + case BlockSink::uart_1_rx: + return 6; + case BlockSink::uart_2_rx: + return 5; + case BlockSink::spi_1_cipo: + case BlockSink::spi_2_cipo: + return 4; + case BlockSink::spi_0_cipo: + return 3; + default: + return 2; } +} + +/** + * A handle to a sink configuration register. This can be used to select + * the source of the handle's associated sink. + */ +template +struct Sink { + CHERI::Capability reg; + const SinkEnum sink; /** - * For a given block input, selects a pin to use for that input via the pin - * multiplexer. + * Select a source to connect to the sink. * - * @param block_input The block input to pinmux. - * @param option The option to select for that block input. This value - * should be less than the value returned by `block_input_options` for the - * given block input. + * To see the sources available for a given sink see the Sonata system + * documentation: + * https://lowrisc.github.io/sonata-system/doc/ip/pinmux/ * - * The meanings of these selections can be found in the documentation: - * https://lowrisc.github.io/sonata-system/doc/ip/pinmux.html + * Note, source 0 disconnects the sink from any source disabling it, + * and source 1 is the default source for any given sink. */ - bool block_input_select(BlockInput block_input, uint8_t option) { - if (option >= block_input_options(block_input)) { - Debug::log("Selected option is not valid for this block."); + bool select(uint8_t source) { + if (source >= sources_number(sink)) { + Debug::log("{} is outside the range of valid sources, [0-{}), of pin {}.", source, sources_number(sink), sink); return false; } - uint16_t registerOffset = static_cast(block_input); - registers[registerOffset] = (1 << option); + *reg = 1 << source; return true; } - /** - * A constructor for the SonataPinmux driver, which takes a bounded - * capability to the pinmux registers. This should be replaced with - * an appropriate `MMIO_CAPABILITY` call in the version of the driver - * that runs in CHERIoT RTOS, rather than baremetal. - */ - SonataPinmux(volatile uint8_t *registers) : registers(registers) {} + /// Disconnect the sink from all available sources. + void disable() { *reg = 1 << SourceDisabled; } + + /// Reset the sink to it's default source. + void default_selection() { *reg = 1 << SourceDefault; } +}; + +namespace { +template +// This is used by `BlockSinks` and `PinSinks` +// to return a capability to a single sink's configuration register. +inline Sink _get_sink(volatile uint8_t *base_register, const SinkEnum sink) { + CHERI::Capability reg = {base_register + static_cast(sink)}; + reg.bounds() = sizeof(uint8_t); + return Sink{reg, sink}; +}; +} // namespace + +/** + * A driver for the Sonata system's pin multiplexed output pins. + * + * The Sonata system's Pin Multiplexer (pinmux) has two sets of registers: the pin sink + * registers and the block sink registers. This structure provides access to the + * pin sinks registers. Pin sinks are output onto the Sonata system's pins, which + * can be connected to a number of block outputs (their sources). The sources each sink + * can connect to are limited. See the documentation for the possible sources for + * a given pin: + * + * https://lowrisc.github.io/sonata-system/doc/ip/pinmux/ + */ +struct PinSinks : private utils::NoCopyNoMove { + volatile uint8_t registers[NumPinSinks]; + + /// Returns a handle to a pin sink (an output pin). + Sink get(PinSink sink) volatile { return _get_sink(registers, sink); }; +}; + +/** + * A driver for the Sonata system's pin multiplexed block inputs. + * + * The Sonata system's Pin Multiplexer (pinmux) has two sets of registers: the pin sink + * registers and the block sink registers. This structure provides access to the + * block sinks registers. Block sinks are inputs into the Sonata system's devices + * that can be connected to a number of system input pins (their sources). The sources + * each sink can connect to are limited. See the documentation for the possible sources + * for a given pin: + * + * https://lowrisc.github.io/sonata-system/doc/ip/pinmux + */ +struct BlockSinks : private utils::NoCopyNoMove { + volatile uint8_t registers[NumBlockSinks]; + + /// Returns a handle to a block sink (a block input). + Sink get(BlockSink sink) volatile { return _get_sink(registers, sink); }; }; +} // namespace SonataPinmux diff --git a/sw/cheri/common/platform-pinmux.hh.tpl b/sw/cheri/common/platform-pinmux.hh.tpl index 614423cde..6302b3456 100644 --- a/sw/cheri/common/platform-pinmux.hh.tpl +++ b/sw/cheri/common/platform-pinmux.hh.tpl @@ -1,195 +1,207 @@ -/** - * Copyright lowRISC contributors. - * Licensed under the Apache License, Version 2.0, see LICENSE for details. - * SPDX-License-Identifier: Apache-2.0 - */ +// SPDX-FileCopyrightText: lowRISC contributors +// SPDX-License-Identifier: Apache-2.0 ${"#"}pragma once ${"#"}include ${"#"}include ${"#"}include +${"#"}include -/** - * A driver for Sonata's Pin Multiplexer (Pinmux). - * - * This driver can be used to select which block output is placed on a given - * output pin, and to select which input pin is provided to a given block - * input. Sonata's pinmux only allows certain selections per output pin / block - * input, which this driver describes. - * - * Rendered documentation is served from: - * https://lowrisc.github.io/sonata-system/doc/ip/pinmux.html - */ -class SonataPinmux : private utils::NoCopyNoMove { - /** - * Flag to set when debugging the driver for UART log messages. - */ - static constexpr bool DebugDriver = false; +namespace SonataPinmux { +/// The number of pin sinks (pin outputs) +static constexpr size_t NumPinSinks = ${len(output_pins)}; - /** - * Helper for conditional debug logs and assertions. - */ - using Debug = ConditionalDebug; +/// The number of block sinks (block inputs) +static constexpr size_t NumBlockSinks = ${len(output_block_ios)}; - /** - * A pointer/capability to the Pin Multiplexer's registers, where - * each sequential byte potentially corresponds to some mapped pinmux - * selector used to select the pin configuration. - */ - volatile uint8_t *registers; +/// Flag to set when debugging the driver for UART log messages. +static constexpr bool DebugDriver = false; - public: - /** - * The Output Pins defined for the Sonata board. These output pins can be - * multiplexed, meaning that they can be changed to output the outputs - * of different blocks (or disabled). The block outputs that can be - * selected are limited, and vary on a per-pin basis. - * - * Documentation sources: - * https://lowrisc.github.io/sonata-system/doc/ip/pinmux.html - * https://github.com/lowRISC/sonata-system/blob/4b72d8c07c727846c6ccb27754352388f3b2ac9a/data/pins_sonata.xdc - * https://github.com/newaetech/sonata-pcb/blob/649b11c2fb758f798966605a07a8b6b68dd434e9/sonata-schematics-r09.pdf - */ - enum class OutputPin : uint16_t { +/// Helper for conditional debug logs and assertions. +using Debug = ConditionalDebug; + +/// The disable bit that disables a sink +constexpr uint8_t SourceDisabled = 0; + +/// The bit that resets a sink to it's default value +constexpr uint8_t SourceDefault = 1; + +/** + * Each pin sink is configured by an 8-bit register. This enum maps pin sink + * names to the offset of their configuration registers. The offsets are relative + * to the first pin sink register. + * + * Documentation sources: + * 1. https://lowrisc.github.io/sonata-system/doc/ip/pinmux/ + * 2. https://github.com/lowRISC/sonata-system/blob/v1.0/data/pins_sonata.xdc + * 3. https://github.com/newaetech/sonata-pcb/blob/649b11c2fb758f798966605a07a8b6b68dd434e9/sonata-schematics-r09.pdf + */ +enum class PinSink : uint16_t { % for output_idx, (pin, _, _) in enumerate(output_pins): - ${pin.doc_name.replace("[","_").replace("]","")} = ${f"{output_idx:#0{5}x}"}, + ${pin.name} = ${f"{output_idx:#0{5}x}"}, % endfor - }; +}; - /** - * The Block Inputs defined for the Sonata board. These block inputs can - * be multiplexed, meaning that they can be changed to take the input of - * different pins (or be disabled). The pin inputs that can be selected - * are limited, and vary on a per-block-input basis. - * - * For reference: - * gpio_0 = Raspberry Pi - * gpio_1 = ArduinoShield - * gpio_2 = Pmod - * - * Documentation source: - * https://lowrisc.github.io/sonata-system/doc/ip/pinmux.html - * */ - enum class BlockInput : uint16_t { +/** + * Each block sink is configured by an 8-bit register. This enum maps block sink + * names to the offset of their configuration registers. The offsets are relative + * to the first block sink register. + * + * For GPIO block reference: + * gpio_0 = Raspberry Pi Header Pins + * gpio_1 = Arduino Shield Header Pins + * gpio_2 = Pmod0 Pins + * gpio_3 = Pmod1 Pins + * gpio_4 = PmodC Pins + * + * Documentation source: + * https://lowrisc.github.io/sonata-system/doc/ip/pinmux/ + */ +enum class BlockSink : uint16_t { % for input_idx, (block_io, possible_pins, num_options) in enumerate(output_block_ios): - ${block_io.doc_name.replace("[","_").replace(".","_").replace("]","")} = ${f"{(0x800+input_idx):#0{5}x}"}, + ${block_io.doc_name} = ${f"{input_idx:#0{5}x}"}, % endfor - }; +}; - /** - * A helper function that returns the number of block outputs that can be - * selected from in the pin multiplexer for a given output pin. This will - * always be at least 2, as option 0 represents 'OFF' i.e. no connection, - * and option 1 represents the default connection. - * - * @param output_pin The output pin to query - * @returns The number of selections available for that output pin - * - * The meanings of these selections can be found in the documentation: - * https://lowrisc.github.io/sonata-system/doc/ip/pinmux.html - */ - static constexpr uint8_t output_pin_options(OutputPin output_pin) { - switch (output_pin) { +/** + * Returns the number of sources available for a pin sink (output pin). + * + * @param pin_sink The pin sink to query. + * @returns The number of sources available for the given sink. + */ +static constexpr uint8_t sources_number(PinSink pin_sink) { + switch (pin_sink) { <% - prev_num_options = 0 + prev_num_options = 0 %> % for (pin, _, num_options) in filter(lambda pin: pin[2] > 2, sorted(output_pins, key=lambda pin: pin[2], reverse=True)): - % if prev_num_options != 0 and prev_num_options != num_options: - return ${prev_num_options}; - % endif - <% - prev_num_options = num_options - %> case OutputPin::${pin.doc_name.replace("[","_").replace("]","")}: + % if prev_num_options != 0 and prev_num_options != num_options: + return ${prev_num_options}; + % endif + <% + prev_num_options = num_options + %> case PinSink::${pin.name}: % endfor % if prev_num_options != 0: - return ${prev_num_options}; + return ${prev_num_options}; % endif - default: - return 2; - } + default: + return 2; } +} - /** - * A helper function that returns the number of input pins that can be - * selected from in the pin multiplexer for a given block input. This will - * always be at least 2, as option 0 represents 'OFF' i.e. no connection, - * and option 1 represents the default connection. - * - * @param block_input The block input to query. - * @returns The number of selections available for that block input. - * - * The meanings of these selections can be found in the documentation: - * https://lowrisc.github.io/sonata-system/doc/ip/pinmux.html - */ - static constexpr uint8_t block_input_options(BlockInput block_input) { - switch (block_input) { +/** + * Returns the number of sources available for a block sink (block input). + * + * @param block_sink The block sink to query. + * @returns The number of sources available for the given sink. + */ +static constexpr uint8_t sources_number(BlockSink block_sink) { + switch (block_sink) { <% - prev_num_options = 0 + prev_num_options = 0 %> % for (block_io, _, num_options) in filter(lambda block: block[2] > 2, sorted(output_block_ios, key=lambda block: block[2], reverse=True)): - % if prev_num_options != 0 and prev_num_options != num_options: - return ${prev_num_options}; - % endif - <% - prev_num_options = num_options - %> case BlockInput::${block_io.doc_name.replace("[","_").replace(".","_").replace("]","")}: + % if prev_num_options != 0 and prev_num_options != num_options: + return ${prev_num_options}; + % endif + <% + prev_num_options = num_options + %> case BlockSink::${block_io.doc_name}: % endfor % if prev_num_options != 0: - return ${prev_num_options}; + return ${prev_num_options}; % endif - default: - return 2; - } + default: + return 2; } +} - /** - * For a given output pin, selects a given block output to use for that pin - * via the pin multiplexer. - * - * @param output_pin The output pin to pinmux. - * @param option The option to select for that pin. This value should be - * less than the value returned by `output_pin_options` for the given pin. - * - * The meanings of these selections can be found in the documentation: - * https://lowrisc.github.io/sonata-system/doc/ip/pinmux.html - */ - bool output_pin_select(OutputPin output_pin, uint8_t option) { - if (option >= output_pin_options(output_pin)) { - Debug::log("Selected option is not valid for this pin."); - return false; - } - uint16_t registerOffset = static_cast(output_pin); - registers[registerOffset] = (1 << option); - return true; - } +/** + * A handle to a sink configuration register. This can be used to select + * the source of the handle's associated sink. + */ +template +struct Sink { + CHERI::Capability reg; + const SinkEnum sink; /** - * For a given block input, selects a pin to use for that input via the pin - * multiplexer. + * Select a source to connect to the sink. * - * @param block_input The block input to pinmux. - * @param option The option to select for that block input. This value - * should be less than the value returned by `block_input_options` for the - * given block input. + * To see the sources available for a given sink see the Sonata system + * documentation: + * https://lowrisc.github.io/sonata-system/doc/ip/pinmux/ * - * The meanings of these selections can be found in the documentation: - * https://lowrisc.github.io/sonata-system/doc/ip/pinmux.html + * Note, source 0 disconnects the sink from any source disabling it, + * and source 1 is the default source for any given sink. */ - bool block_input_select(BlockInput block_input, uint8_t option) { - if (option >= block_input_options(block_input)) { - Debug::log("Selected option is not valid for this block."); + bool select(uint8_t source) { + if (source >= sources_number(sink)) { + Debug::log("{} is outside the range of valid sources, [0-{}), of pin {}.", source, sources_number(sink), sink); return false; } - uint16_t registerOffset = static_cast(block_input); - registers[registerOffset] = (1 << option); + *reg = 1 << source; return true; } - /** - * A constructor for the SonataPinmux driver, which takes a bounded - * capability to the pinmux registers. This should be replaced with - * an appropriate `MMIO_CAPABILITY` call in the version of the driver - * that runs in CHERIoT RTOS, rather than baremetal. - */ - SonataPinmux(volatile uint8_t *registers) : registers(registers) {} + /// Disconnect the sink from all available sources. + void disable() { *reg = 1 << SourceDisabled; } + + /// Reset the sink to it's default source. + void default_selection() { *reg = 1 << SourceDefault; } +}; + +namespace { +template +// This is used by `BlockSinks` and `PinSinks` +// to return a capability to a single sink's configuration register. +inline Sink _get_sink(volatile uint8_t *base_register, const SinkEnum sink) { + CHERI::Capability reg = {base_register + static_cast(sink)}; + reg.bounds() = sizeof(uint8_t); + return Sink{reg, sink}; +}; +} // namespace + +/** + * A driver for the Sonata system's pin multiplexed output pins. + * + * The Sonata system's Pin Multiplexer (pinmux) has two sets of registers: the pin sink + * registers and the block sink registers. This structure provides access to the + * pin sinks registers. Pin sinks are output onto the Sonata system's pins, which + * can be connected to a number of block outputs (their sources). The sources each sink + * can connect to are limited. See the documentation for the possible sources for + * a given pin: + * + * https://lowrisc.github.io/sonata-system/doc/ip/pinmux/ + */ +struct PinSinks : private utils::NoCopyNoMove { + volatile uint8_t registers[NumPinSinks]; + + /// Returns a handle to a pin sink (an output pin). + Sink get(PinSink sink) volatile { + return _get_sink(registers, sink); + }; +}; + +/** + * A driver for the Sonata system's pin multiplexed block inputs. + * + * The Sonata system's Pin Multiplexer (pinmux) has two sets of registers: the pin sink + * registers and the block sink registers. This structure provides access to the + * block sinks registers. Block sinks are inputs into the Sonata system's devices + * that can be connected to a number of system input pins (their sources). The sources + * each sink can connect to are limited. See the documentation for the possible sources + * for a given pin: + * + * https://lowrisc.github.io/sonata-system/doc/ip/pinmux + */ +struct BlockSinks : private utils::NoCopyNoMove { + volatile uint8_t registers[NumBlockSinks]; + + /// Returns a handle to a block sink (a block input). + Sink get(BlockSink sink) volatile { + return _get_sink(registers, sink); + }; }; +} // namespace SonataPinmux diff --git a/sw/cheri/common/sonata-devices.hh b/sw/cheri/common/sonata-devices.hh index 7ffbad776..caf3ddb07 100644 --- a/sw/cheri/common/sonata-devices.hh +++ b/sw/cheri/common/sonata-devices.hh @@ -29,7 +29,9 @@ typedef volatile SonataSpi *SpiPtr; typedef volatile OpenTitanUsbdev *UsbdevPtr; typedef volatile uint32_t *HyperramPtr; typedef PLIC::SonataPlic *PlicPtr; -typedef SonataPinmux *PinmuxPtr; +typedef volatile SonataPinmux::PinSinks *PinSinksPtr; +typedef volatile SonataPinmux::BlockSinks *BlockSinksPtr; +using PinmuxPtrs = std::pair; [[maybe_unused]] static GpioPtr gpio_ptr(CapRoot root) { CHERI::Capability gpio = root.cast(); @@ -75,3 +77,21 @@ typedef SonataPinmux *PinmuxPtr; usbdev.bounds() = USBDEV_BOUNDS; return usbdev; } + +[[maybe_unused]] static PinSinksPtr pin_sinks_ptr(CapRoot root) { + using namespace SonataPinmux; + CHERI::Capability pinSinks = root.cast(); + pinSinks.address() = PINMUX_PIN_SINKS_ADDRESS; + pinSinks.bounds() = PINMUX_PIN_SINKS_BOUNDS; + static_assert(sizeof(PinSinks) == PINMUX_PIN_SINKS_BOUNDS); + return pinSinks; +} + +[[maybe_unused]] static BlockSinksPtr block_sinks_ptr(CapRoot root) { + using namespace SonataPinmux; + CHERI::Capability blockSinks = root.cast(); + blockSinks.address() = PINMUX_BLOCK_SINKS_ADDRESS; + blockSinks.bounds() = PINMUX_BLOCK_SINKS_BOUNDS; + static_assert(sizeof(BlockSinks) == PINMUX_BLOCK_SINKS_BOUNDS); + return blockSinks; +} diff --git a/sw/cheri/tests/pinmux_tests.hh b/sw/cheri/tests/pinmux_tests.hh index 8d90eb535..151d95d64 100644 --- a/sw/cheri/tests/pinmux_tests.hh +++ b/sw/cheri/tests/pinmux_tests.hh @@ -16,7 +16,7 @@ #include #include -using namespace CHERI; +using namespace SonataPinmux; /** * Configures the number of test iterations to perform. @@ -53,9 +53,6 @@ static constexpr uint32_t UartTestBytes = 100; static constexpr uint32_t GpioWaitUsec = 20; // short wire bridge between FGPA pins. static constexpr uint32_t GpioTestLength = 10; -static constexpr uint8_t PmxToDisabled = 0; -static constexpr uint8_t PmxToDefault = 1; - /** * Test pinmux by enabling and disabling the UART1 TX pin output and UART1 RX * block input. Tests the UART itself by sending and receiving some data over @@ -68,36 +65,37 @@ static constexpr uint8_t PmxToDefault = 1; * * Returns the number of failures during the test. */ -static int pinmux_uart_test(SonataPinmux *pinmux, ds::xoroshiro::P32R8 &prng, UartPtr uart1) { - constexpr uint8_t PmxMikroBusUartTransmitToUartTx1 = 1; - constexpr uint8_t PmxUartReceive1ToMb8 = 4; +static int pinmux_uart_test(PinmuxPtrs sinks, ds::xoroshiro::P32R8 &prng, UartPtr uart1) { + constexpr uint8_t PmxUartReceive1ToMb8 = 4; - int failures = 0; + auto mb7 = std::get(sinks)->get(PinSink::mb7); + auto uart_1_rx = std::get(sinks)->get(BlockSink::uart_1_rx); + int failures = 0; // Mux UART1 over mikroBus P7 RX & TX via default. - failures += !pinmux->output_pin_select(SonataPinmux::OutputPin::mb7, PmxMikroBusUartTransmitToUartTx1); - failures += !pinmux->block_input_select(SonataPinmux::BlockInput::uart_1_rx, PmxUartReceive1ToMb8); + mb7.default_selection(); + failures += !uart_1_rx.select(PmxUartReceive1ToMb8); // Check that messages are sent and received via UART1 failures += !uart_send_receive_test(prng, uart1, UartTimeoutUsec, UartTestBytes); // Disable UART1 TX through pinmux, and check the test now fails (no TX sent) - failures += !pinmux->output_pin_select(SonataPinmux::OutputPin::mb7, PmxToDisabled); + mb7.disable(); failures += uart_send_receive_test(prng, uart1, UartTimeoutUsec, UartTestBytes); // Re-enable UART1 TX and disable UART1 RX through pinmux, and check that the test // still fails (no RX received) - failures += !pinmux->output_pin_select(SonataPinmux::OutputPin::mb7, PmxMikroBusUartTransmitToUartTx1); - failures += !pinmux->block_input_select(SonataPinmux::BlockInput::uart_1_rx, PmxToDisabled); + mb7.default_selection(); + uart_1_rx.disable(); failures += uart_send_receive_test(prng, uart1, UartTimeoutUsec, UartTestBytes); // Re-enable UART1 RX and check the test now passes again - failures += !pinmux->block_input_select(SonataPinmux::BlockInput::uart_1_rx, PmxUartReceive1ToMb8); + failures += !uart_1_rx.select(PmxUartReceive1ToMb8); failures += !uart_send_receive_test(prng, uart1, UartTimeoutUsec, UartTestBytes); // Reset muxed pins to not interfere with future tests - failures += !pinmux->output_pin_select(SonataPinmux::OutputPin::mb7, PmxToDefault); - failures += !pinmux->block_input_select(SonataPinmux::BlockInput::uart_1_rx, PmxToDefault); + mb7.default_selection(); + uart_1_rx.default_selection(); return failures; } @@ -124,19 +122,23 @@ static void reset_spi_flash(SpiPtr spi) { * via pinmux and repeats the JEDEC ID read, checking that it succeeds. * Returns the number of failures during the test. */ -static int pinmux_spi_flash_test(SonataPinmux *pinmux, SpiPtr spi) { +static int pinmux_spi_flash_test(PinmuxPtrs sinks, SpiPtr spi) { constexpr uint8_t PmxPmod1Io1ToSpi2Cs = 2; constexpr uint8_t PmxPmod1Io2ToSpi2Copi = 2; constexpr uint8_t PmxPmod1Io4ToSpi2Sclk = 2; constexpr uint8_t PmxSpi2CipoToPmod1Io3 = 3; - int failures = 0; + int failures = 0; + auto pmod1_1 = std::get(sinks)->get(PinSink::pmod1_1); + auto spi_2_cipo = std::get(sinks)->get(BlockSink::spi_2_cipo); + auto pmod1_2 = std::get(sinks)->get(PinSink::pmod1_2); + auto pmod1_4 = std::get(sinks)->get(PinSink::pmod1_4); // Ensure the SPI Flash pins are enabled using Pinmux - failures += !pinmux->output_pin_select(SonataPinmux::OutputPin::pmod1_1, PmxPmod1Io1ToSpi2Cs); - failures += !pinmux->block_input_select(SonataPinmux::BlockInput::spi_2_cipo, PmxSpi2CipoToPmod1Io3); - failures += !pinmux->output_pin_select(SonataPinmux::OutputPin::pmod1_2, PmxPmod1Io2ToSpi2Copi); - failures += !pinmux->output_pin_select(SonataPinmux::OutputPin::pmod1_4, PmxPmod1Io4ToSpi2Sclk); + failures += !pmod1_1.select(PmxPmod1Io1ToSpi2Cs); + failures += !spi_2_cipo.select(PmxSpi2CipoToPmod1Io3); + failures += !pmod1_2.select(PmxPmod1Io2ToSpi2Copi); + failures += !pmod1_4.select(PmxPmod1Io4ToSpi2Sclk); // Configure the SPI to be MSB-first. spi->wait_idle(); @@ -148,10 +150,10 @@ static int pinmux_spi_flash_test(SonataPinmux *pinmux, SpiPtr spi) { // Disable the SPI Flash pins through pinmux spi->wait_idle(); - failures += !pinmux->output_pin_select(SonataPinmux::OutputPin::pmod1_1, PmxToDisabled); - failures += !pinmux->block_input_select(SonataPinmux::BlockInput::spi_2_cipo, PmxToDisabled); - failures += !pinmux->output_pin_select(SonataPinmux::OutputPin::pmod1_2, PmxToDisabled); - failures += !pinmux->output_pin_select(SonataPinmux::OutputPin::pmod1_4, PmxToDisabled); + pmod1_1.disable(); + spi_2_cipo.disable(); + pmod1_2.disable(); + pmod1_4.disable(); reset_spi_flash(spi); // Run the JEDEC ID Test again; we expect it to fail. @@ -159,10 +161,10 @@ static int pinmux_spi_flash_test(SonataPinmux *pinmux, SpiPtr spi) { // Re-enable the SPI Flash pins through pinmux spi->wait_idle(); - failures += !pinmux->output_pin_select(SonataPinmux::OutputPin::pmod1_1, PmxPmod1Io1ToSpi2Cs); - failures += !pinmux->block_input_select(SonataPinmux::BlockInput::spi_2_cipo, PmxSpi2CipoToPmod1Io3); - failures += !pinmux->output_pin_select(SonataPinmux::OutputPin::pmod1_2, PmxPmod1Io2ToSpi2Copi); - failures += !pinmux->output_pin_select(SonataPinmux::OutputPin::pmod1_4, PmxPmod1Io4ToSpi2Sclk); + failures += !pmod1_1.select(PmxPmod1Io1ToSpi2Cs); + failures += !spi_2_cipo.select(PmxSpi2CipoToPmod1Io3); + failures += !pmod1_2.select(PmxPmod1Io2ToSpi2Copi); + failures += !pmod1_4.select(PmxPmod1Io4ToSpi2Sclk); reset_spi_flash(spi); // Run the JEDEC ID Test one more time; it should pass. @@ -170,7 +172,7 @@ static int pinmux_spi_flash_test(SonataPinmux *pinmux, SpiPtr spi) { // Disable specifically the Chip Select through Pinmux. spi->wait_idle(); - failures += !pinmux->output_pin_select(SonataPinmux::OutputPin::pmod1_1, PmxToDisabled); + pmod1_1.disable(); reset_spi_flash(spi); // Run the JEDEC ID Test again; we expect it to fail. @@ -178,17 +180,17 @@ static int pinmux_spi_flash_test(SonataPinmux *pinmux, SpiPtr spi) { // Re-enable the Chip Select through Pinmux. spi->wait_idle(); - failures += !pinmux->output_pin_select(SonataPinmux::OutputPin::pmod1_1, PmxPmod1Io1ToSpi2Cs); + failures += !pmod1_1.select(PmxPmod1Io1ToSpi2Cs); reset_spi_flash(spi); // Run the JEDEC ID Test again; it should pass. failures += !spi_n25q256a_read_jedec_id(spi); // Reset muxed pins to not interfere with future tests - failures += !pinmux->output_pin_select(SonataPinmux::OutputPin::pmod1_1, PmxToDefault); - failures += !pinmux->block_input_select(SonataPinmux::BlockInput::spi_2_cipo, PmxToDefault); - failures += !pinmux->output_pin_select(SonataPinmux::OutputPin::pmod1_2, PmxToDefault); - failures += !pinmux->output_pin_select(SonataPinmux::OutputPin::pmod1_4, PmxToDefault); + pmod1_1.default_selection(); + spi_2_cipo.default_selection(); + pmod1_2.default_selection(); + pmod1_4.default_selection(); return failures; } @@ -204,19 +206,23 @@ static int pinmux_spi_flash_test(SonataPinmux *pinmux, SpiPtr spi) { * * Returns the number of failures during the test. */ -static int pinmux_i2c_test(SonataPinmux *pinmux, I2cPtr i2c0, I2cPtr i2c1) { +static int pinmux_i2c_test(PinSinksPtr pinSinks, I2cPtr i2c0, I2cPtr i2c1) { constexpr uint8_t PmxRPiHat27ToI2cSda0 = 1; constexpr uint8_t PmxRPiHat28ToI2cScl0 = 1; constexpr uint8_t PmxRPiHat3ToI2cSda1 = 1; constexpr uint8_t PmxRPiHat5ToI2cScl1 = 1; - int failures = 0; + int failures = 0; + auto rph_g0 = pinSinks->get(PinSink::rph_g0); + auto rph_g1 = pinSinks->get(PinSink::rph_g1); + auto rph_g2_sda = pinSinks->get(PinSink::rph_g2_sda); + auto rph_g3_scl = pinSinks->get(PinSink::rph_g3_scl); // Ensure the RPI Hat I2C pins are enabled via Pinmux - failures += !pinmux->output_pin_select(SonataPinmux::OutputPin::rph_g0, PmxRPiHat27ToI2cSda0); - failures += !pinmux->output_pin_select(SonataPinmux::OutputPin::rph_g1, PmxRPiHat28ToI2cScl0); - failures += !pinmux->output_pin_select(SonataPinmux::OutputPin::rph_g2_sda, PmxRPiHat3ToI2cSda1); - failures += !pinmux->output_pin_select(SonataPinmux::OutputPin::rph_g3_scl, PmxRPiHat5ToI2cScl1); + failures += !rph_g0.select(PmxRPiHat27ToI2cSda0); + failures += !rph_g1.select(PmxRPiHat28ToI2cScl0); + failures += !rph_g2_sda.select(PmxRPiHat3ToI2cSda1); + failures += !rph_g3_scl.select(PmxRPiHat5ToI2cScl1); // Run the normal I2C RPI Hat ID_EEPROM and WHO_AM_I tests failures += i2c_rpi_hat_id_eeprom_test(i2c0); @@ -224,34 +230,34 @@ static int pinmux_i2c_test(SonataPinmux *pinmux, I2cPtr i2c0, I2cPtr i2c1) { // Disable the RPI Hat I2C0 output pins, and check that the ID EEPROM test // now fails (and the WHOAMI test still succeeds). - failures += !pinmux->output_pin_select(SonataPinmux::OutputPin::rph_g0, PmxToDisabled); - failures += !pinmux->output_pin_select(SonataPinmux::OutputPin::rph_g1, PmxToDisabled); + rph_g0.disable(); + rph_g1.disable(); failures += (i2c_rpi_hat_id_eeprom_test(i2c0) == 0); failures += i2c_rpi_hat_imu_whoami_test(i2c1); // Re-enables the RPI Hat I2C0 pins and disables the I2C1 pins, and check that the // ID EEPROM test now passes. and the WHOAMI test now fails. - failures += !pinmux->output_pin_select(SonataPinmux::OutputPin::rph_g0, PmxRPiHat27ToI2cSda0); - failures += !pinmux->output_pin_select(SonataPinmux::OutputPin::rph_g1, PmxRPiHat28ToI2cScl0); - failures += !pinmux->output_pin_select(SonataPinmux::OutputPin::rph_g2_sda, PmxToDisabled); - failures += !pinmux->output_pin_select(SonataPinmux::OutputPin::rph_g3_scl, PmxToDisabled); + failures += !rph_g0.select(PmxRPiHat27ToI2cSda0); + failures += !rph_g1.select(PmxRPiHat28ToI2cScl0); + rph_g2_sda.disable(); + rph_g3_scl.disable(); reset_i2c_controller(i2c0); failures += i2c_rpi_hat_id_eeprom_test(i2c0); failures += (i2c_rpi_hat_imu_whoami_test(i2c1) == 0); // Re-enables both the RPI Hat I2C0 and I2C1 pins via pinmux, and checks that both // tests now pass again. - failures += !pinmux->output_pin_select(SonataPinmux::OutputPin::rph_g2_sda, PmxRPiHat3ToI2cSda1); - failures += !pinmux->output_pin_select(SonataPinmux::OutputPin::rph_g3_scl, PmxRPiHat5ToI2cScl1); + failures += !rph_g2_sda.select(PmxRPiHat3ToI2cSda1); + failures += !rph_g3_scl.select(PmxRPiHat5ToI2cScl1); reset_i2c_controller(i2c1); failures += i2c_rpi_hat_id_eeprom_test(i2c0); failures += i2c_rpi_hat_imu_whoami_test(i2c1); // Reset muxed pins to not interfere with future tests - failures += !pinmux->output_pin_select(SonataPinmux::OutputPin::rph_g0, PmxToDefault); - failures += !pinmux->output_pin_select(SonataPinmux::OutputPin::rph_g1, PmxToDefault); - failures += !pinmux->output_pin_select(SonataPinmux::OutputPin::rph_g2_sda, PmxToDefault); - failures += !pinmux->output_pin_select(SonataPinmux::OutputPin::rph_g3_scl, PmxToDefault); + rph_g0.default_selection(); + rph_g1.default_selection(); + rph_g2_sda.default_selection(); + rph_g3_scl.default_selection(); return failures; } @@ -265,39 +271,41 @@ static int pinmux_i2c_test(SonataPinmux *pinmux, I2cPtr i2c0, I2cPtr i2c1) { * * Returns the number of failures durign the test. */ -static int pinmux_gpio_test(SonataPinmux *pinmux, SonataGpioFull *gpio) { +static int pinmux_gpio_test(PinmuxPtrs sinks, SonataGpioFull *gpio) { constexpr uint8_t PmxArduinoD8ToGpios_1_8 = 1; constexpr uint8_t PmxArduinoGpio9ToAhTmpio9 = 1; constexpr GpioPin GpioPinInput = {GpioInstance::ArduinoShield, 9}; constexpr GpioPin GpioPinOutput = {GpioInstance::ArduinoShield, 8}; - int failures = 0; + int failures = 0; + auto ah_tmpio8 = std::get(sinks)->get(PinSink::ah_tmpio8); + auto gpio_1_ios_9 = std::get(sinks)->get(BlockSink::gpio_1_ios_9); // Configure the Arduino D9 GPIO as input and D8 as output. set_gpio_output_enable(gpio, GpioPinOutput, true); set_gpio_output_enable(gpio, GpioPinInput, false); // Ensure the GPIO (Arduino Shield D8 & D9) are enabled via Pinmux - failures += !pinmux->output_pin_select(SonataPinmux::OutputPin::ah_tmpio8, PmxArduinoD8ToGpios_1_8); - failures += !pinmux->block_input_select(SonataPinmux::BlockInput::gpio_1_ios_9, PmxArduinoGpio9ToAhTmpio9); + failures += !ah_tmpio8.select(PmxArduinoD8ToGpios_1_8); + failures += !gpio_1_ios_9.select(PmxArduinoGpio9ToAhTmpio9); // Check that reading & writing from/to GPIO works as expected. failures += !gpio_write_read_test(gpio, GpioPinOutput, GpioPinInput, GpioWaitUsec, GpioTestLength); // Disable the GPIO via pinmux, and check that the test now fails. - failures += !pinmux->output_pin_select(SonataPinmux::OutputPin::ah_tmpio8, PmxToDisabled); - failures += !pinmux->block_input_select(SonataPinmux::BlockInput::gpio_1_ios_9, PmxToDisabled); + ah_tmpio8.disable(); + gpio_1_ios_9.disable(); failures += gpio_write_read_test(gpio, GpioPinOutput, GpioPinInput, GpioWaitUsec, GpioTestLength); // Re-enable the GPIO via pinmux, and check that the test passes once more - failures += !pinmux->output_pin_select(SonataPinmux::OutputPin::ah_tmpio8, PmxArduinoD8ToGpios_1_8); - failures += !pinmux->block_input_select(SonataPinmux::BlockInput::gpio_1_ios_9, PmxArduinoGpio9ToAhTmpio9); + failures += !ah_tmpio8.select(PmxArduinoD8ToGpios_1_8); + failures += !gpio_1_ios_9.select(PmxArduinoGpio9ToAhTmpio9); failures += !gpio_write_read_test(gpio, GpioPinOutput, GpioPinInput, GpioWaitUsec, GpioTestLength); // Reset muxed pins to not interfere with future tests - failures += !pinmux->output_pin_select(SonataPinmux::OutputPin::ah_tmpio8, PmxToDefault); - failures += !pinmux->block_input_select(SonataPinmux::BlockInput::gpio_1_ios_9, PmxToDefault); + ah_tmpio8.default_selection(); + gpio_1_ios_9.default_selection(); return failures; } @@ -314,7 +322,7 @@ static int pinmux_gpio_test(SonataPinmux *pinmux, SonataGpioFull *gpio) { * * Returns the number of failures during the test. */ -static int pinmux_mux_test(SonataPinmux *pinmux, ds::xoroshiro::P32R8 &prng, UartPtr uart1, SonataGpioFull *gpio) { +static int pinmux_mux_test(PinmuxPtrs sinks, ds::xoroshiro::P32R8 &prng, UartPtr uart1, SonataGpioFull *gpio) { constexpr uint8_t PmxArduinoD1ToUartTx1 = 1; constexpr uint8_t PmxArduinoD1ToGpio_1_1 = 2; constexpr uint8_t PmxUartReceive1ToAhTmpio0 = 3; @@ -323,15 +331,18 @@ static int pinmux_mux_test(SonataPinmux *pinmux, ds::xoroshiro::P32R8 &prng, Uar constexpr GpioPin GpioPinInput = {GpioInstance::ArduinoShield, 0}; constexpr GpioPin GpioPinOutput = {GpioInstance::ArduinoShield, 1}; - int failures = 0; + int failures = 0; + auto ah_tmpio1 = std::get(sinks)->get(PinSink::ah_tmpio1); + auto uart_1_rx = std::get(sinks)->get(BlockSink::uart_1_rx); + auto gpio_1_ios_0 = std::get(sinks)->get(BlockSink::gpio_1_ios_0); // Set the Arduino GPIO D0 as input and D1 as output. set_gpio_output_enable(gpio, GpioPinOutput, true); set_gpio_output_enable(gpio, GpioPinInput, false); // Mux UART1 over Arduino Shield D0 (RX) & D1 (TX) - failures += !pinmux->output_pin_select(SonataPinmux::OutputPin::ah_tmpio1, PmxArduinoD1ToUartTx1); - failures += !pinmux->block_input_select(SonataPinmux::BlockInput::uart_1_rx, PmxUartReceive1ToAhTmpio0); + failures += !ah_tmpio1.select(PmxArduinoD1ToUartTx1); + failures += !uart_1_rx.select(PmxUartReceive1ToAhTmpio0); // Test that UART1 works over the muxed Arduino Shield D0 & D1 pins, // and that GPIO does not work, as these pins are not muxed for GPIO. @@ -339,8 +350,8 @@ static int pinmux_mux_test(SonataPinmux *pinmux, ds::xoroshiro::P32R8 &prng, Uar failures += gpio_write_read_test(gpio, GpioPinOutput, GpioPinInput, GpioWaitUsec, GpioTestLength); // Mux GPIO over Arduino Shield D0 (GPIO input) & D1 (GPIO output) - failures += !pinmux->output_pin_select(SonataPinmux::OutputPin::ah_tmpio1, PmxArduinoD1ToGpio_1_1); - failures += !pinmux->block_input_select(SonataPinmux::BlockInput::gpio_1_ios_0, PmxArduinoGpio0ToAhTmpio0); + failures += !ah_tmpio1.select(PmxArduinoD1ToGpio_1_1); + failures += !gpio_1_ios_0.select(PmxArduinoGpio0ToAhTmpio0); // Test that UART1 no longer works (no longer muxed over D0 & D1), // and that our muxed GPIO now works. @@ -348,15 +359,15 @@ static int pinmux_mux_test(SonataPinmux *pinmux, ds::xoroshiro::P32R8 &prng, Uar failures += !gpio_write_read_test(gpio, GpioPinOutput, GpioPinInput, GpioWaitUsec, GpioTestLength); // Mux back to UART1 again, and test that UART again passes and GPIO fails. - failures += !pinmux->output_pin_select(SonataPinmux::OutputPin::ah_tmpio1, PmxArduinoD1ToUartTx1); - failures += !pinmux->block_input_select(SonataPinmux::BlockInput::uart_1_rx, PmxUartReceive1ToAhTmpio0); + failures += !ah_tmpio1.select(PmxArduinoD1ToUartTx1); + failures += !uart_1_rx.select(PmxUartReceive1ToAhTmpio0); failures += !uart_send_receive_test(prng, uart1, UartTimeoutUsec, UartTestBytes); failures += gpio_write_read_test(gpio, GpioPinOutput, GpioPinInput, GpioWaitUsec, GpioTestLength); // Reset muxed pins to not interfere with future tests - failures += !pinmux->output_pin_select(SonataPinmux::OutputPin::ah_tmpio1, PmxToDefault); - failures += !pinmux->block_input_select(SonataPinmux::BlockInput::uart_1_rx, PmxToDefault); - failures += !pinmux->block_input_select(SonataPinmux::BlockInput::gpio_1_ios_0, PmxToDefault); + ah_tmpio1.default_selection(); + uart_1_rx.default_selection(); + gpio_1_ios_0.default_selection(); return failures; } @@ -365,11 +376,8 @@ static int pinmux_mux_test(SonataPinmux *pinmux, ds::xoroshiro::P32R8 &prng, Uar * Run the whole suite of pinmux tests. */ void pinmux_tests(CapRoot root, Log &log) { - // Create a bounded capability for pinmux & initialise the driver - Capability pinmux = root.cast(); - pinmux.address() = PINMUX_ADDRESS; - pinmux.bounds() = PINMUX_BOUNDS; - SonataPinmux Pinmux = SonataPinmux(pinmux); + // Create a bounded capability for pinmux sinks + PinmuxPtrs sinks = std::pair{pin_sinks_ptr(root), block_sinks_ptr(root)}; // Create bounded capabilities for other devices, to be used in testing. SpiPtr spi = spi_ptr(root, 4); @@ -398,31 +406,31 @@ void pinmux_tests(CapRoot root, Log &log) { if (PINMUX_PMOD1_PMODSF3_AVAILABLE) { log.print(" Running SPI Flash Pinmux test... "); - failures = pinmux_spi_flash_test(&Pinmux, spi); + failures = pinmux_spi_flash_test(sinks, spi); test_failed |= (failures > 0); write_test_result(log, failures); } if (I2C_RPI_HAT_AVAILABLE) { log.print(" Running I2C Pinmux test... "); - failures = pinmux_i2c_test(&Pinmux, i2c0, i2c1); + failures = pinmux_i2c_test(std::get(sinks), i2c0, i2c1); test_failed |= (failures > 0); write_test_result(log, failures); } if (PINMUX_CABLE_CONNECTIONS_AVAILABLE) { log.print(" Running GPIO Pinmux test... "); - failures = pinmux_gpio_test(&Pinmux, &gpio_full); + failures = pinmux_gpio_test(sinks, &gpio_full); test_failed |= (failures > 0); write_test_result(log, failures); log.print(" Running UART Pinmux test... "); - failures = pinmux_uart_test(&Pinmux, prng, uart1); + failures = pinmux_uart_test(sinks, prng, uart1); test_failed |= (failures > 0); write_test_result(log, failures); log.print(" Running Mux test... "); - failures = pinmux_mux_test(&Pinmux, prng, uart1, &gpio_full); + failures = pinmux_mux_test(sinks, prng, uart1, &gpio_full); test_failed |= (failures > 0); write_test_result(log, failures); } diff --git a/sw/cheri/tests/spi_tests.hh b/sw/cheri/tests/spi_tests.hh index 66f1245da..7d384375d 100644 --- a/sw/cheri/tests/spi_tests.hh +++ b/sw/cheri/tests/spi_tests.hh @@ -497,15 +497,12 @@ void spi_tests(CapRoot root, Log &log) { SpiFlash spi_flash(spis[2]); - // Create a bounded capability for pinmux & initialise the driver - Capability pinmux = root.cast(); - pinmux.address() = PINMUX_ADDRESS; - pinmux.bounds() = PINMUX_BOUNDS; - SonataPinmux Pinmux = SonataPinmux(pinmux); + // Create a bounded capability for pinmux + auto spi_2_cipo = block_sinks_ptr(root)->get(SonataPinmux::BlockSink::spi_2_cipo); if (SPI_TEST_EXT_LOOPBACK_CONN == 4) { // Mux SPI2 to receive from MB3. - Pinmux.block_input_select(SonataPinmux::BlockInput::spi_2_cipo, 2); + spi_2_cipo.select(2); } // Initialise 8-bit PRNG for use in random test data @@ -590,6 +587,6 @@ void spi_tests(CapRoot root, Log &log) { if (SPI_TEST_EXT_LOOPBACK_CONN == 4) { // Mux SPI2 back to its default - Pinmux.block_input_select(SonataPinmux::BlockInput::spi_2_cipo, 1); + spi_2_cipo.default_selection(); } } diff --git a/sw/common/defs.h b/sw/common/defs.h index 6d7c61c29..087cdaa69 100644 --- a/sw/common/defs.h +++ b/sw/common/defs.h @@ -61,8 +61,10 @@ #define USBDEV_ADDRESS (0x8040'0000) #define USBDEV_BOUNDS (0x0000'1000) -#define PINMUX_ADDRESS (0x8000'5000) -#define PINMUX_BOUNDS (0x0000'1000) +#define PINMUX_PIN_SINKS_ADDRESS (0x8000'5000) +#define PINMUX_PIN_SINKS_BOUNDS (0x0000'0055) +#define PINMUX_BLOCK_SINKS_ADDRESS (0x8000'5800) +#define PINMUX_BLOCK_SINKS_BOUNDS (0x0000'0046) #define PLIC_ADDRESS (0x8800'0000) #define PLIC_BOUNDS (0x0040'0000) diff --git a/util/top_gen/generator.py b/util/top_gen/generator.py index 967a755c1..e4853d913 100644 --- a/util/top_gen/generator.py +++ b/util/top_gen/generator.py @@ -55,10 +55,11 @@ def io_idx_str(self) -> str: @property def doc_name(self) -> str: uid = self.uid + suffix = f"_{uid.io_index}" if uid.io_index is not None else "" if self.only_instance: - return f"{uid.block}_{uid.io}{self.io_idx_str}" + return f"{uid.block}_{uid.io}{suffix}" else: - return f"{uid.block}[{uid.instance}].{uid.io}{self.io_idx_str}" + return f"{uid.block}_{uid.instance}_{uid.io}{suffix}" @dataclass(frozen=True)