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