499e89367f8d59e61fa5daab11dc1cc6cc2ad6cb
[oweals/u-boot.git] / board / Marvell / mvebu_armada-8k / board.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2016 Stefan Roese <sr@denx.de>
4  */
5
6 #include <common.h>
7 #include <dm.h>
8 #include <i2c.h>
9 #include <init.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 /*
17  * Information specific to the DB-88F7040 eval board. We strive to use
18  * DT for such platform specfic configurations. At some point, this
19  * might be removed here and implemented via DT.
20  */
21 /* IO expander I2C device */
22 #define I2C_IO_EXP_ADDR         0x21
23 #define I2C_IO_CFG_REG_0        0x6
24 #define I2C_IO_DATA_OUT_REG_0   0x2
25 /* VBus enable */
26 #define I2C_IO_REG_0_USB_H0_OFF 0
27 #define I2C_IO_REG_0_USB_H1_OFF 1
28 #define I2C_IO_REG_VBUS         ((1 << I2C_IO_REG_0_USB_H0_OFF) | \
29                                  (1 << I2C_IO_REG_0_USB_H1_OFF))
30 /* Current limit */
31 #define I2C_IO_REG_0_USB_H0_CL  4
32 #define I2C_IO_REG_0_USB_H1_CL  5
33 #define I2C_IO_REG_CL           ((1 << I2C_IO_REG_0_USB_H0_CL) | \
34                                  (1 << I2C_IO_REG_0_USB_H1_CL))
35
36 static int usb_enabled = 0;
37
38 /* Board specific xHCI dis-/enable code */
39
40 /*
41  * Set USB VBUS signals (via I2C IO expander/GPIO) as output and set
42  * output value as disabled
43  *
44  * Set USB Current Limit signals (via I2C IO expander/GPIO) as output
45  * and set output value as enabled
46  */
47 int board_xhci_config(void)
48 {
49         struct udevice *dev;
50         int ret;
51         u8 buf[8];
52
53         if (of_machine_is_compatible("marvell,armada7040-db")) {
54                 /* Configure IO exander PCA9555: 7bit address 0x21 */
55                 ret = i2c_get_chip_for_busnum(0, I2C_IO_EXP_ADDR, 1, &dev);
56                 if (ret) {
57                         printf("Cannot find PCA9555: %d\n", ret);
58                         return 0;
59                 }
60
61                 /*
62                  * Read configuration (direction) and set VBUS pin as output
63                  * (reset pin = output)
64                  */
65                 ret = dm_i2c_read(dev, I2C_IO_CFG_REG_0, buf, 1);
66                 if (ret) {
67                         printf("Failed to read IO expander value via I2C\n");
68                         return -EIO;
69                 }
70                 buf[0] &= ~I2C_IO_REG_VBUS;
71                 buf[0] &= ~I2C_IO_REG_CL;
72                 ret = dm_i2c_write(dev, I2C_IO_CFG_REG_0, buf, 1);
73                 if (ret) {
74                         printf("Failed to set IO expander via I2C\n");
75                         return -EIO;
76                 }
77
78                 /* Read output value and configure it */
79                 ret = dm_i2c_read(dev, I2C_IO_DATA_OUT_REG_0, buf, 1);
80                 if (ret) {
81                         printf("Failed to read IO expander value via I2C\n");
82                         return -EIO;
83                 }
84                 buf[0] &= ~I2C_IO_REG_VBUS;
85                 buf[0] |= I2C_IO_REG_CL;
86                 ret = dm_i2c_write(dev, I2C_IO_DATA_OUT_REG_0, buf, 1);
87                 if (ret) {
88                         printf("Failed to set IO expander via I2C\n");
89                         return -EIO;
90                 }
91
92                 mdelay(500); /* required delay to let output value settle */
93         }
94
95         return 0;
96 }
97
98 int board_xhci_enable(fdt_addr_t base)
99 {
100         struct udevice *dev;
101         int ret;
102         u8 buf[8];
103
104         if (of_machine_is_compatible("marvell,armada7040-db")) {
105                 /*
106                  * This function enables all USB ports simultaniously,
107                  * it only needs to get called once
108                  */
109                 if (usb_enabled)
110                         return 0;
111
112                 /* Configure IO exander PCA9555: 7bit address 0x21 */
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                 /* Read VBUS output value */
120                 ret = dm_i2c_read(dev, I2C_IO_DATA_OUT_REG_0, buf, 1);
121                 if (ret) {
122                         printf("Failed to read IO expander value via I2C\n");
123                         return -EIO;
124                 }
125
126                 /* Enable VBUS power: Set output value of VBUS pin as enabled */
127                 buf[0] |= I2C_IO_REG_VBUS;
128                 ret = dm_i2c_write(dev, I2C_IO_DATA_OUT_REG_0, buf, 1);
129                 if (ret) {
130                         printf("Failed to set IO expander via I2C\n");
131                         return -EIO;
132                 }
133
134                 mdelay(500); /* required delay to let output value settle */
135                 usb_enabled = 1;
136         }
137
138         return 0;
139 }
140
141 int board_early_init_f(void)
142 {
143         /* Nothing to do (yet), perhaps later some pin-muxing etc */
144
145         return 0;
146 }
147
148 int board_init(void)
149 {
150         /* adress of boot parameters */
151         gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100;
152
153         return 0;
154 }
155
156 int board_late_init(void)
157 {
158         /* Pre-configure the USB ports (overcurrent, VBus) */
159         board_xhci_config();
160
161         return 0;
162 }