github.com/usbarmory/tamago@v0.0.0-20240508072735-8612bbe1e454/board/nxp/mx6ullevk/enet.go (about)

     1  // MCIMX6ULL-EVK support for tamago/arm
     2  // https://github.com/usbarmory/tamago
     3  //
     4  // Copyright (c) WithSecure Corporation
     5  // https://foundry.withsecure.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 mx6ullevk
    11  
    12  import (
    13  	"errors"
    14  
    15  	"github.com/usbarmory/tamago/soc/nxp/enet"
    16  	"github.com/usbarmory/tamago/soc/nxp/imx6ul"
    17  	"github.com/usbarmory/tamago/soc/nxp/iomuxc"
    18  )
    19  
    20  // Ethernet PHY configuration constants.
    21  //
    22  // On the MCIMX6ULL-EVK the ENET MACs are each connected to an KSZ8081RNB PHY,
    23  // this board package configures them at 100 Mbps / Full-duplex mode.
    24  const (
    25  	KSZ_CTRL    = 0x00
    26  	CTRL_RESET  = 15
    27  	CTRL_SPEED  = 13
    28  	CTRL_DUPLEX = 8
    29  
    30  	KSZ_INT = 0x1b
    31  
    32  	KSZ_PHYCTRL2  = 0x1f
    33  	CTRL2_HP_MDIX = 15
    34  	CTRL2_RMII    = 7
    35  	CTRL2_LED     = 4
    36  )
    37  
    38  const (
    39  	// ENET1 MUX
    40  	IOMUXC_SW_MUX_CTL_PAD_ENET1_RX_DATA0 = 0x020e00c4
    41  	IOMUXC_SW_MUX_CTL_PAD_ENET1_RX_DATA1 = 0x020e00c8
    42  	IOMUXC_SW_MUX_CTL_PAD_ENET1_RX_EN    = 0x020e00cc
    43  	IOMUXC_SW_MUX_CTL_PAD_ENET1_TX_DATA0 = 0x020e00d0
    44  	IOMUXC_SW_MUX_CTL_PAD_ENET1_TX_DATA1 = 0x020e00d4
    45  	IOMUXC_SW_MUX_CTL_PAD_ENET1_TX_EN    = 0x020e00d8
    46  	IOMUXC_SW_MUX_CTL_PAD_ENET1_TX_CLK   = 0x020e00dc
    47  	IOMUXC_SW_MUX_CTL_PAD_ENET1_RX_ER    = 0x020e00e0
    48  
    49  	// ENET1 PAD
    50  	IOMUXC_SW_PAD_CTL_PAD_ENET1_RX_DATA0 = 0x020e0350
    51  	IOMUXC_SW_PAD_CTL_PAD_ENET1_RX_DATA1 = 0x020e0354
    52  	IOMUXC_SW_PAD_CTL_PAD_ENET1_RX_EN    = 0x020e0358
    53  	IOMUXC_SW_PAD_CTL_PAD_ENET1_TX_DATA0 = 0x020e035c
    54  	IOMUXC_SW_PAD_CTL_PAD_ENET1_TX_DATA1 = 0x020e0360
    55  	IOMUXC_SW_PAD_CTL_PAD_ENET1_TX_EN    = 0x020e0364
    56  	IOMUXC_SW_PAD_CTL_PAD_ENET1_TX_CLK   = 0x020e0368
    57  	IOMUXC_SW_PAD_CTL_PAD_ENET1_RX_ER    = 0x020e036c
    58  
    59  	// ENET1 SELECT INPUT
    60  	IOMUXC_ENET1_REF_CLK1_SELECT_INPUT  = 0x020e0574
    61  	IOMUXC_ENET1_MAC0_MDIO_SELECT_INPUT = 0x020e0578
    62  
    63  	// ENET2 MUX
    64  	IOMUXC_SW_MUX_CTL_PAD_ENET2_RX_DATA0 = 0x020e00e4
    65  	IOMUXC_SW_MUX_CTL_PAD_ENET2_RX_DATA1 = 0x020e00e8
    66  	IOMUXC_SW_MUX_CTL_PAD_ENET2_RX_EN    = 0x020e00ec
    67  	IOMUXC_SW_MUX_CTL_PAD_ENET2_TX_DATA0 = 0x020e00f0
    68  	IOMUXC_SW_MUX_CTL_PAD_ENET2_TX_DATA1 = 0x020e00f4
    69  	IOMUXC_SW_MUX_CTL_PAD_ENET2_TX_EN    = 0x020e00f8
    70  	IOMUXC_SW_MUX_CTL_PAD_ENET2_TX_CLK   = 0x020e00fc
    71  	IOMUXC_SW_MUX_CTL_PAD_ENET2_RX_ER    = 0x020e0100
    72  
    73  	// ENET2 PAD
    74  	IOMUXC_SW_PAD_CTL_PAD_ENET2_RX_DATA0 = 0x020e0370
    75  	IOMUXC_SW_PAD_CTL_PAD_ENET2_RX_DATA1 = 0x020e0374
    76  	IOMUXC_SW_PAD_CTL_PAD_ENET2_RX_EN    = 0x020e0378
    77  	IOMUXC_SW_PAD_CTL_PAD_ENET2_TX_DATA0 = 0x020e037c
    78  	IOMUXC_SW_PAD_CTL_PAD_ENET2_TX_DATA1 = 0x020e0380
    79  	IOMUXC_SW_PAD_CTL_PAD_ENET2_TX_EN    = 0x020e0384
    80  	IOMUXC_SW_PAD_CTL_PAD_ENET2_TX_CLK   = 0x020e0388
    81  	IOMUXC_SW_PAD_CTL_PAD_ENET2_RX_ER    = 0x020e038c
    82  
    83  	// ENET2 SELECT INPUT
    84  	IOMUXC_ENET2_REF_CLK2_SELECT_INPUT  = 0x020e057c
    85  	IOMUXC_ENET2_MAC0_MDIO_SELECT_INPUT = 0x020e0580
    86  
    87  	// MDIO
    88  	IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO06 = 0x020e0074
    89  	IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO06 = 0x020e0300
    90  
    91  	// MDC
    92  	IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO07 = 0x020e0304
    93  	IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO07 = 0x020e0078
    94  
    95  	IOMUX_ALT0 = 0
    96  	IOMUX_ALT1 = 1
    97  	IOMUX_ALT4 = 4
    98  
    99  	DAISY_ENET1_TX_CLK_ALT4     = 0b10
   100  	DAISY_ENET2_TX_CLK_ALT4     = 0b10
   101  	DAISY_ENET1_GPIO1_IO06_ALT0 = 0
   102  	DAISY_ENET2_GPIO1_IO06_ALT1 = 1
   103  )
   104  
   105  func init() {
   106  	imx6ul.ENET1.EnablePHY = EnablePHY
   107  	imx6ul.ENET2.EnablePHY = EnablePHY
   108  
   109  	imx6ul.ENET1.RMII = true
   110  	imx6ul.ENET2.RMII = true
   111  }
   112  
   113  func configurePHYPad(mux uint32, pad uint32, daisy uint32, mode uint32, ctl uint32) (p *iomuxc.Pad) {
   114  	p = &iomuxc.Pad{
   115  		Mux:   mux,
   116  		Pad:   pad,
   117  		Daisy: daisy,
   118  	}
   119  
   120  	p.Mode(mode)
   121  	p.Ctl(ctl)
   122  
   123  	return
   124  }
   125  
   126  func ctl50() uint32 {
   127  	return (iomuxc.SW_PAD_CTL_DSE_2_R0_6 << iomuxc.SW_PAD_CTL_DSE) |
   128  		(iomuxc.SW_PAD_CTL_SPEED_50MHZ << iomuxc.SW_PAD_CTL_SPEED) |
   129  		(1 << iomuxc.SW_PAD_CTL_PUE) | (1 << iomuxc.SW_PAD_CTL_PKE) |
   130  		(iomuxc.SW_PAD_CTL_PUS_PULL_UP_100K << iomuxc.SW_PAD_CTL_PUS) |
   131  		(1 << iomuxc.SW_PAD_CTL_HYS)
   132  }
   133  
   134  func ctl100() uint32 {
   135  	return (iomuxc.SW_PAD_CTL_DSE_2_R0_6 << iomuxc.SW_PAD_CTL_DSE) |
   136  		(iomuxc.SW_PAD_CTL_SPEED_100MHZ << iomuxc.SW_PAD_CTL_SPEED) |
   137  		(1 << iomuxc.SW_PAD_CTL_PUE) | (1 << iomuxc.SW_PAD_CTL_PKE) |
   138  		(iomuxc.SW_PAD_CTL_PUS_PULL_UP_100K << iomuxc.SW_PAD_CTL_PUS) |
   139  		(1 << iomuxc.SW_PAD_CTL_HYS)
   140  }
   141  
   142  func configurePHY1Pads() {
   143  	// 50 Mhz pad
   144  	ctl50 := ctl50()
   145  	// 100 Mhz pad
   146  	ctl100 := ctl100()
   147  
   148  	// [ALT0] ENET1_RDATA01
   149  	configurePHYPad(
   150  		IOMUXC_SW_MUX_CTL_PAD_ENET1_RX_DATA0,
   151  		IOMUXC_SW_PAD_CTL_PAD_ENET1_RX_DATA0,
   152  		0, IOMUX_ALT0, ctl100)
   153  
   154  	// [ALT0] ENET1_RDATA01
   155  	configurePHYPad(
   156  		IOMUXC_SW_MUX_CTL_PAD_ENET1_RX_DATA1,
   157  		IOMUXC_SW_PAD_CTL_PAD_ENET1_RX_DATA1,
   158  		0, IOMUX_ALT0, ctl100)
   159  
   160  	// [ALT0] ENET1_RX_EN
   161  	configurePHYPad(
   162  		IOMUXC_SW_MUX_CTL_PAD_ENET1_RX_EN,
   163  		IOMUXC_SW_PAD_CTL_PAD_ENET1_RX_EN,
   164  		0, IOMUX_ALT0, ctl100)
   165  
   166  	// [ALT0] ENET1_TDATA00
   167  	configurePHYPad(
   168  		IOMUXC_SW_MUX_CTL_PAD_ENET1_TX_DATA0,
   169  		IOMUXC_SW_PAD_CTL_PAD_ENET1_TX_DATA0,
   170  		0, IOMUX_ALT0, ctl100)
   171  
   172  	// [ALT0] ENET1_TDATA01
   173  	configurePHYPad(
   174  		IOMUXC_SW_MUX_CTL_PAD_ENET1_TX_DATA1,
   175  		IOMUXC_SW_PAD_CTL_PAD_ENET1_TX_DATA1,
   176  		0, IOMUX_ALT0, ctl100)
   177  
   178  	// [ALT0] ENET1_TX_EN
   179  	configurePHYPad(
   180  		IOMUXC_SW_MUX_CTL_PAD_ENET1_TX_EN,
   181  		IOMUXC_SW_PAD_CTL_PAD_ENET1_TX_EN,
   182  		0, IOMUX_ALT0, ctl100)
   183  
   184  	// [ALT4] ENET1_REF_CLK / SION ENABLED
   185  	pad := configurePHYPad(
   186  		IOMUXC_SW_MUX_CTL_PAD_ENET1_TX_CLK,
   187  		IOMUXC_SW_PAD_CTL_PAD_ENET1_TX_CLK,
   188  		IOMUXC_ENET1_REF_CLK1_SELECT_INPUT,
   189  		IOMUX_ALT4, ctl50)
   190  	pad.Select(DAISY_ENET1_TX_CLK_ALT4)
   191  	pad.SoftwareInput(true)
   192  
   193  	// [ALT0] ENET1_RX_ER
   194  	configurePHYPad(
   195  		IOMUXC_SW_MUX_CTL_PAD_ENET1_RX_ER,
   196  		IOMUXC_SW_PAD_CTL_PAD_ENET1_RX_ER,
   197  		0, IOMUX_ALT0, ctl100)
   198  
   199  	// [ALT0] ENET1_MDIO
   200  	pad = configurePHYPad(
   201  		IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO06,
   202  		IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO06,
   203  		IOMUXC_ENET1_MAC0_MDIO_SELECT_INPUT,
   204  		IOMUX_ALT0, ctl100)
   205  	pad.Select(DAISY_ENET1_GPIO1_IO06_ALT0)
   206  
   207  	// [ALT0] ENET1_MDC
   208  	configurePHYPad(
   209  		IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO07,
   210  		IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO07,
   211  		0, IOMUX_ALT0, ctl100)
   212  }
   213  
   214  func configurePHY2Pads() {
   215  	// 50 Mhz pad
   216  	ctl50 := ctl50()
   217  	// 100 Mhz pad
   218  	ctl100 := ctl100()
   219  
   220  	// [ALT0] ENET2_RDATA01
   221  	configurePHYPad(
   222  		IOMUXC_SW_MUX_CTL_PAD_ENET2_RX_DATA0,
   223  		IOMUXC_SW_PAD_CTL_PAD_ENET2_RX_DATA0,
   224  		0, IOMUX_ALT0, ctl100)
   225  
   226  	// [ALT0] ENET2_RDATA01
   227  	configurePHYPad(
   228  		IOMUXC_SW_MUX_CTL_PAD_ENET2_RX_DATA1,
   229  		IOMUXC_SW_PAD_CTL_PAD_ENET2_RX_DATA1,
   230  		0, IOMUX_ALT0, ctl100)
   231  
   232  	// [ALT0] ENET2_RX_EN
   233  	configurePHYPad(
   234  		IOMUXC_SW_MUX_CTL_PAD_ENET2_RX_EN,
   235  		IOMUXC_SW_PAD_CTL_PAD_ENET2_RX_EN,
   236  		0, IOMUX_ALT0, ctl100)
   237  
   238  	// [ALT0] ENET2_TDATA00
   239  	configurePHYPad(
   240  		IOMUXC_SW_MUX_CTL_PAD_ENET2_TX_DATA0,
   241  		IOMUXC_SW_PAD_CTL_PAD_ENET2_TX_DATA0,
   242  		0, IOMUX_ALT0, ctl100)
   243  
   244  	// [ALT0] ENET2_TDATA01
   245  	configurePHYPad(
   246  		IOMUXC_SW_MUX_CTL_PAD_ENET2_TX_DATA1,
   247  		IOMUXC_SW_PAD_CTL_PAD_ENET2_TX_DATA1,
   248  		0, IOMUX_ALT0, ctl100)
   249  
   250  	// [ALT0] ENET2_TX_EN
   251  	configurePHYPad(
   252  		IOMUXC_SW_MUX_CTL_PAD_ENET2_TX_EN,
   253  		IOMUXC_SW_PAD_CTL_PAD_ENET2_TX_EN,
   254  		0, IOMUX_ALT0, ctl100)
   255  
   256  	// [ALT4] ENET2_REF_CLK / SION ENABLED
   257  	pad := configurePHYPad(
   258  		IOMUXC_SW_MUX_CTL_PAD_ENET2_TX_CLK,
   259  		IOMUXC_SW_PAD_CTL_PAD_ENET2_TX_CLK,
   260  		IOMUXC_ENET2_REF_CLK2_SELECT_INPUT,
   261  		IOMUX_ALT4, ctl50)
   262  	pad.Select(DAISY_ENET2_TX_CLK_ALT4)
   263  	pad.SoftwareInput(true)
   264  
   265  	// [ALT0] ENET2_RX_ER
   266  	configurePHYPad(
   267  		IOMUXC_SW_MUX_CTL_PAD_ENET2_RX_ER,
   268  		IOMUXC_SW_PAD_CTL_PAD_ENET2_RX_ER,
   269  		0, IOMUX_ALT0, ctl100)
   270  
   271  	// [ALT0] ENET2_MDIO
   272  	pad = configurePHYPad(
   273  		IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO06,
   274  		IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO06,
   275  		IOMUXC_ENET2_MAC0_MDIO_SELECT_INPUT,
   276  		IOMUX_ALT1, ctl100)
   277  	pad.Select(DAISY_ENET2_GPIO1_IO06_ALT1)
   278  
   279  	// [ALT0] ENET2_MDC
   280  	configurePHYPad(
   281  		IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO07,
   282  		IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO07,
   283  		0, IOMUX_ALT1, ctl100)
   284  }
   285  
   286  func EnablePHY(eth *enet.ENET) error {
   287  	var pa int
   288  
   289  	switch eth.Index {
   290  	case 1:
   291  		pa = 2
   292  		configurePHY1Pads()
   293  	case 2:
   294  		pa = 1
   295  		configurePHY2Pads()
   296  	default:
   297  		return errors.New("invalid index")
   298  	}
   299  
   300  	// Software reset
   301  	eth.WritePHYRegister(pa, KSZ_CTRL, (1 << CTRL_RESET))
   302  	// HP Auto MDI/MDI-X mode, RMII 50MHz, LEDs: Activity/Link
   303  	eth.WritePHYRegister(pa, KSZ_PHYCTRL2, (1<<CTRL2_HP_MDIX)|(1<<CTRL2_RMII)|(1<<CTRL2_LED))
   304  	// 100 Mbps, Full-duplex
   305  	eth.WritePHYRegister(pa, KSZ_CTRL, (1<<CTRL_SPEED)|(1<<CTRL_DUPLEX))
   306  	// enable interrupts
   307  	eth.WritePHYRegister(pa, KSZ_INT, 0xff00)
   308  
   309  	return nil
   310  }