Home | History | Annotate | Download | only in mvebu_armada-37xx
      1 // SPDX-License-Identifier: GPL-2.0+
      2 /*
      3  * Copyright (C) 2016 Stefan Roese <sr (at) denx.de>
      4  */
      5 
      6 #include <common.h>
      7 #include <dm.h>
      8 #include <i2c.h>
      9 #include <phy.h>
     10 #include <asm/io.h>
     11 #include <asm/arch/cpu.h>
     12 #include <asm/arch/soc.h>
     13 
     14 DECLARE_GLOBAL_DATA_PTR;
     15 
     16 /* IO expander I2C device */
     17 #define I2C_IO_EXP_ADDR		0x22
     18 #define I2C_IO_CFG_REG_0	0x6
     19 #define I2C_IO_DATA_OUT_REG_0	0x2
     20 #define I2C_IO_REG_0_SATA_OFF	2
     21 #define I2C_IO_REG_0_USB_H_OFF	1
     22 
     23 /* The pin control values are the same for DB and Espressobin */
     24 #define PINCTRL_NB_REG_VALUE	0x000173fa
     25 #define PINCTRL_SB_REG_VALUE	0x00007a23
     26 
     27 /* Ethernet switch registers */
     28 /* SMI addresses for multi-chip mode */
     29 #define MVEBU_PORT_CTRL_SMI_ADDR(p)	(16 + (p))
     30 #define MVEBU_SW_G2_SMI_ADDR		(28)
     31 
     32 /* Multi-chip mode */
     33 #define MVEBU_SW_SMI_DATA_REG		(1)
     34 #define MVEBU_SW_SMI_CMD_REG		(0)
     35  #define SW_SMI_CMD_REG_ADDR_OFF	0
     36  #define SW_SMI_CMD_DEV_ADDR_OFF	5
     37  #define SW_SMI_CMD_SMI_OP_OFF		10
     38  #define SW_SMI_CMD_SMI_MODE_OFF	12
     39  #define SW_SMI_CMD_SMI_BUSY_OFF	15
     40 
     41 /* Single-chip mode */
     42 /* Switch Port Registers */
     43 #define MVEBU_SW_LINK_CTRL_REG		(1)
     44 #define MVEBU_SW_PORT_CTRL_REG		(4)
     45 
     46 /* Global 2 Registers */
     47 #define MVEBU_G2_SMI_PHY_CMD_REG	(24)
     48 #define MVEBU_G2_SMI_PHY_DATA_REG	(25)
     49 
     50 int board_early_init_f(void)
     51 {
     52 	return 0;
     53 }
     54 
     55 int board_init(void)
     56 {
     57 	/* adress of boot parameters */
     58 	gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100;
     59 
     60 	return 0;
     61 }
     62 
     63 /* Board specific AHCI / SATA enable code */
     64 int board_ahci_enable(void)
     65 {
     66 	struct udevice *dev;
     67 	int ret;
     68 	u8 buf[8];
     69 
     70 	/* Only DB requres this configuration */
     71 	if (!of_machine_is_compatible("marvell,armada-3720-db"))
     72 		return 0;
     73 
     74 	/* Configure IO exander PCA9555: 7bit address 0x22 */
     75 	ret = i2c_get_chip_for_busnum(0, I2C_IO_EXP_ADDR, 1, &dev);
     76 	if (ret) {
     77 		printf("Cannot find PCA9555: %d\n", ret);
     78 		return 0;
     79 	}
     80 
     81 	ret = dm_i2c_read(dev, I2C_IO_CFG_REG_0, buf, 1);
     82 	if (ret) {
     83 		printf("Failed to read IO expander value via I2C\n");
     84 		return -EIO;
     85 	}
     86 
     87 	/*
     88 	 * Enable SATA power via IO expander connected via I2C by setting
     89 	 * the corresponding bit to output mode to enable power for SATA
     90 	 */
     91 	buf[0] &= ~(1 << I2C_IO_REG_0_SATA_OFF);
     92 	ret = dm_i2c_write(dev, I2C_IO_CFG_REG_0, buf, 1);
     93 	if (ret) {
     94 		printf("Failed to set IO expander via I2C\n");
     95 		return -EIO;
     96 	}
     97 
     98 	return 0;
     99 }
    100 
    101 /* Board specific xHCI enable code */
    102 int board_xhci_enable(fdt_addr_t base)
    103 {
    104 	struct udevice *dev;
    105 	int ret;
    106 	u8 buf[8];
    107 
    108 	/* Only DB requres this configuration */
    109 	if (!of_machine_is_compatible("marvell,armada-3720-db"))
    110 		return 0;
    111 
    112 	/* Configure IO exander PCA9555: 7bit address 0x22 */
    113 	ret = i2c_get_chip_for_busnum(0, I2C_IO_EXP_ADDR, 1, &dev);
    114 	if (ret) {
    115 		printf("Cannot find PCA9555: %d\n", ret);
    116 		return 0;
    117 	}
    118 
    119 	printf("Enable USB VBUS\n");
    120 
    121 	/*
    122 	 * Read configuration (direction) and set VBUS pin as output
    123 	 * (reset pin = output)
    124 	 */
    125 	ret = dm_i2c_read(dev, I2C_IO_CFG_REG_0, buf, 1);
    126 	if (ret) {
    127 		printf("Failed to read IO expander value via I2C\n");
    128 		return -EIO;
    129 	}
    130 	buf[0] &= ~(1 << I2C_IO_REG_0_USB_H_OFF);
    131 	ret = dm_i2c_write(dev, I2C_IO_CFG_REG_0, buf, 1);
    132 	if (ret) {
    133 		printf("Failed to set IO expander via I2C\n");
    134 		return -EIO;
    135 	}
    136 
    137 	/* Read VBUS output value and disable it */
    138 	ret = dm_i2c_read(dev, I2C_IO_DATA_OUT_REG_0, buf, 1);
    139 	if (ret) {
    140 		printf("Failed to read IO expander value via I2C\n");
    141 		return -EIO;
    142 	}
    143 	buf[0] &= ~(1 << I2C_IO_REG_0_USB_H_OFF);
    144 	ret = dm_i2c_write(dev, I2C_IO_DATA_OUT_REG_0, buf, 1);
    145 	if (ret) {
    146 		printf("Failed to set IO expander via I2C\n");
    147 		return -EIO;
    148 	}
    149 
    150 	/*
    151 	 * Required delay for configuration to settle - must wait for
    152 	 * power on port is disabled in case VBUS signal was high,
    153 	 * required 3 seconds delay to let VBUS signal fully settle down
    154 	 */
    155 	mdelay(3000);
    156 
    157 	/* Enable VBUS power: Set output value of VBUS pin as enabled */
    158 	buf[0] |= (1 << I2C_IO_REG_0_USB_H_OFF);
    159 	ret = dm_i2c_write(dev, I2C_IO_DATA_OUT_REG_0, buf, 1);
    160 	if (ret) {
    161 		printf("Failed to set IO expander via I2C\n");
    162 		return -EIO;
    163 	}
    164 
    165 	mdelay(500); /* required delay to let output value settle */
    166 
    167 	return 0;
    168 }
    169 
    170 /* Helper function for accessing switch devices in multi-chip connection mode */
    171 static int mii_multi_chip_mode_write(struct mii_dev *bus, int dev_smi_addr,
    172 				     int smi_addr, int reg, u16 value)
    173 {
    174 	u16 smi_cmd = 0;
    175 
    176 	if (bus->write(bus, dev_smi_addr, 0,
    177 		       MVEBU_SW_SMI_DATA_REG, value) != 0) {
    178 		printf("Error writing to the PHY addr=%02x reg=%02x\n",
    179 		       smi_addr, reg);
    180 		return -EFAULT;
    181 	}
    182 
    183 	smi_cmd = (1 << SW_SMI_CMD_SMI_BUSY_OFF) |
    184 		  (1 << SW_SMI_CMD_SMI_MODE_OFF) |
    185 		  (1 << SW_SMI_CMD_SMI_OP_OFF) |
    186 		  (smi_addr << SW_SMI_CMD_DEV_ADDR_OFF) |
    187 		  (reg << SW_SMI_CMD_REG_ADDR_OFF);
    188 	if (bus->write(bus, dev_smi_addr, 0,
    189 		       MVEBU_SW_SMI_CMD_REG, smi_cmd) != 0) {
    190 		printf("Error writing to the PHY addr=%02x reg=%02x\n",
    191 		       smi_addr, reg);
    192 		return -EFAULT;
    193 	}
    194 
    195 	return 0;
    196 }
    197 
    198 /* Bring-up board-specific network stuff */
    199 int board_network_enable(struct mii_dev *bus)
    200 {
    201 	if (!of_machine_is_compatible("marvell,armada-3720-espressobin"))
    202 		return 0;
    203 
    204 	/*
    205 	 * FIXME: remove this code once Topaz driver gets available
    206 	 * A3720 Community Board Only
    207 	 * Configure Topaz switch (88E6341)
    208 	 * Set port 0,1,2,3 to forwarding Mode (through Switch Port registers)
    209 	 */
    210 	mii_multi_chip_mode_write(bus, 1, MVEBU_PORT_CTRL_SMI_ADDR(0),
    211 				  MVEBU_SW_PORT_CTRL_REG, 0x7f);
    212 	mii_multi_chip_mode_write(bus, 1, MVEBU_PORT_CTRL_SMI_ADDR(1),
    213 				  MVEBU_SW_PORT_CTRL_REG, 0x7f);
    214 	mii_multi_chip_mode_write(bus, 1, MVEBU_PORT_CTRL_SMI_ADDR(2),
    215 				  MVEBU_SW_PORT_CTRL_REG, 0x7f);
    216 	mii_multi_chip_mode_write(bus, 1, MVEBU_PORT_CTRL_SMI_ADDR(3),
    217 				  MVEBU_SW_PORT_CTRL_REG, 0x7f);
    218 
    219 	/* RGMII Delay on Port 0 (CPU port), force link to 1000Mbps */
    220 	mii_multi_chip_mode_write(bus, 1, MVEBU_PORT_CTRL_SMI_ADDR(0),
    221 				  MVEBU_SW_LINK_CTRL_REG, 0xe002);
    222 
    223 	/* Power up PHY 1, 2, 3 (through Global 2 registers) */
    224 	mii_multi_chip_mode_write(bus, 1, MVEBU_SW_G2_SMI_ADDR,
    225 				  MVEBU_G2_SMI_PHY_DATA_REG, 0x1140);
    226 	mii_multi_chip_mode_write(bus, 1, MVEBU_SW_G2_SMI_ADDR,
    227 				  MVEBU_G2_SMI_PHY_CMD_REG, 0x9620);
    228 	mii_multi_chip_mode_write(bus, 1, MVEBU_SW_G2_SMI_ADDR,
    229 				  MVEBU_G2_SMI_PHY_CMD_REG, 0x9640);
    230 	mii_multi_chip_mode_write(bus, 1, MVEBU_SW_G2_SMI_ADDR,
    231 				  MVEBU_G2_SMI_PHY_CMD_REG, 0x9660);
    232 
    233 	return 0;
    234 }
    235