1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2633fa0e7SStefan Roese /*
3633fa0e7SStefan Roese * Copyright (C) 2016 Stefan Roese <sr@denx.de>
4633fa0e7SStefan Roese */
5633fa0e7SStefan Roese
6633fa0e7SStefan Roese #include <common.h>
7acd3b076SStefan Roese #include <dm.h>
8633fa0e7SStefan Roese #include <i2c.h>
9633fa0e7SStefan Roese #include <asm/io.h>
10633fa0e7SStefan Roese #include <asm/arch/cpu.h>
11633fa0e7SStefan Roese #include <asm/arch/soc.h>
12633fa0e7SStefan Roese
13633fa0e7SStefan Roese DECLARE_GLOBAL_DATA_PTR;
14633fa0e7SStefan Roese
15acd3b076SStefan Roese /*
16acd3b076SStefan Roese * Information specific to the DB-88F7040 eval board. We strive to use
17acd3b076SStefan Roese * DT for such platform specfic configurations. At some point, this
18acd3b076SStefan Roese * might be removed here and implemented via DT.
19acd3b076SStefan Roese */
20633fa0e7SStefan Roese /* IO expander I2C device */
21633fa0e7SStefan Roese #define I2C_IO_EXP_ADDR 0x21
22633fa0e7SStefan Roese #define I2C_IO_CFG_REG_0 0x6
23633fa0e7SStefan Roese #define I2C_IO_DATA_OUT_REG_0 0x2
24633fa0e7SStefan Roese /* VBus enable */
25633fa0e7SStefan Roese #define I2C_IO_REG_0_USB_H0_OFF 0
26633fa0e7SStefan Roese #define I2C_IO_REG_0_USB_H1_OFF 1
27633fa0e7SStefan Roese #define I2C_IO_REG_VBUS ((1 << I2C_IO_REG_0_USB_H0_OFF) | \
28633fa0e7SStefan Roese (1 << I2C_IO_REG_0_USB_H1_OFF))
29633fa0e7SStefan Roese /* Current limit */
30633fa0e7SStefan Roese #define I2C_IO_REG_0_USB_H0_CL 4
31633fa0e7SStefan Roese #define I2C_IO_REG_0_USB_H1_CL 5
32633fa0e7SStefan Roese #define I2C_IO_REG_CL ((1 << I2C_IO_REG_0_USB_H0_CL) | \
33633fa0e7SStefan Roese (1 << I2C_IO_REG_0_USB_H1_CL))
34633fa0e7SStefan Roese
35633fa0e7SStefan Roese static int usb_enabled = 0;
36633fa0e7SStefan Roese
37633fa0e7SStefan Roese /* Board specific xHCI dis-/enable code */
38633fa0e7SStefan Roese
39633fa0e7SStefan Roese /*
40633fa0e7SStefan Roese * Set USB VBUS signals (via I2C IO expander/GPIO) as output and set
41633fa0e7SStefan Roese * output value as disabled
42633fa0e7SStefan Roese *
43633fa0e7SStefan Roese * Set USB Current Limit signals (via I2C IO expander/GPIO) as output
44633fa0e7SStefan Roese * and set output value as enabled
45633fa0e7SStefan Roese */
board_xhci_config(void)46633fa0e7SStefan Roese int board_xhci_config(void)
47633fa0e7SStefan Roese {
48633fa0e7SStefan Roese struct udevice *dev;
49633fa0e7SStefan Roese int ret;
50633fa0e7SStefan Roese u8 buf[8];
51633fa0e7SStefan Roese
52acd3b076SStefan Roese if (of_machine_is_compatible("marvell,armada7040-db")) {
53633fa0e7SStefan Roese /* Configure IO exander PCA9555: 7bit address 0x21 */
54633fa0e7SStefan Roese ret = i2c_get_chip_for_busnum(0, I2C_IO_EXP_ADDR, 1, &dev);
55633fa0e7SStefan Roese if (ret) {
56633fa0e7SStefan Roese printf("Cannot find PCA9555: %d\n", ret);
57633fa0e7SStefan Roese return 0;
58633fa0e7SStefan Roese }
59633fa0e7SStefan Roese
60633fa0e7SStefan Roese /*
61633fa0e7SStefan Roese * Read configuration (direction) and set VBUS pin as output
62633fa0e7SStefan Roese * (reset pin = output)
63633fa0e7SStefan Roese */
64633fa0e7SStefan Roese ret = dm_i2c_read(dev, I2C_IO_CFG_REG_0, buf, 1);
65633fa0e7SStefan Roese if (ret) {
66633fa0e7SStefan Roese printf("Failed to read IO expander value via I2C\n");
67633fa0e7SStefan Roese return -EIO;
68633fa0e7SStefan Roese }
69633fa0e7SStefan Roese buf[0] &= ~I2C_IO_REG_VBUS;
70633fa0e7SStefan Roese buf[0] &= ~I2C_IO_REG_CL;
71633fa0e7SStefan Roese ret = dm_i2c_write(dev, I2C_IO_CFG_REG_0, buf, 1);
72633fa0e7SStefan Roese if (ret) {
73633fa0e7SStefan Roese printf("Failed to set IO expander via I2C\n");
74633fa0e7SStefan Roese return -EIO;
75633fa0e7SStefan Roese }
76633fa0e7SStefan Roese
77633fa0e7SStefan Roese /* Read output value and configure it */
78633fa0e7SStefan Roese ret = dm_i2c_read(dev, I2C_IO_DATA_OUT_REG_0, buf, 1);
79633fa0e7SStefan Roese if (ret) {
80633fa0e7SStefan Roese printf("Failed to read IO expander value via I2C\n");
81633fa0e7SStefan Roese return -EIO;
82633fa0e7SStefan Roese }
83633fa0e7SStefan Roese buf[0] &= ~I2C_IO_REG_VBUS;
84633fa0e7SStefan Roese buf[0] |= I2C_IO_REG_CL;
85633fa0e7SStefan Roese ret = dm_i2c_write(dev, I2C_IO_DATA_OUT_REG_0, buf, 1);
86633fa0e7SStefan Roese if (ret) {
87633fa0e7SStefan Roese printf("Failed to set IO expander via I2C\n");
88633fa0e7SStefan Roese return -EIO;
89633fa0e7SStefan Roese }
90633fa0e7SStefan Roese
91633fa0e7SStefan Roese mdelay(500); /* required delay to let output value settle */
92acd3b076SStefan Roese }
93633fa0e7SStefan Roese
94633fa0e7SStefan Roese return 0;
95633fa0e7SStefan Roese }
96633fa0e7SStefan Roese
board_xhci_enable(fdt_addr_t base)97d3d036afSJon Nettleton int board_xhci_enable(fdt_addr_t base)
98633fa0e7SStefan Roese {
99633fa0e7SStefan Roese struct udevice *dev;
100633fa0e7SStefan Roese int ret;
101633fa0e7SStefan Roese u8 buf[8];
102633fa0e7SStefan Roese
103acd3b076SStefan Roese if (of_machine_is_compatible("marvell,armada7040-db")) {
104633fa0e7SStefan Roese /*
105633fa0e7SStefan Roese * This function enables all USB ports simultaniously,
106633fa0e7SStefan Roese * it only needs to get called once
107633fa0e7SStefan Roese */
108633fa0e7SStefan Roese if (usb_enabled)
109633fa0e7SStefan Roese return 0;
110633fa0e7SStefan Roese
111633fa0e7SStefan Roese /* Configure IO exander PCA9555: 7bit address 0x21 */
112633fa0e7SStefan Roese ret = i2c_get_chip_for_busnum(0, I2C_IO_EXP_ADDR, 1, &dev);
113633fa0e7SStefan Roese if (ret) {
114633fa0e7SStefan Roese printf("Cannot find PCA9555: %d\n", ret);
115633fa0e7SStefan Roese return 0;
116633fa0e7SStefan Roese }
117633fa0e7SStefan Roese
118633fa0e7SStefan Roese /* Read VBUS output value */
119633fa0e7SStefan Roese ret = dm_i2c_read(dev, I2C_IO_DATA_OUT_REG_0, buf, 1);
120633fa0e7SStefan Roese if (ret) {
121633fa0e7SStefan Roese printf("Failed to read IO expander value via I2C\n");
122633fa0e7SStefan Roese return -EIO;
123633fa0e7SStefan Roese }
124633fa0e7SStefan Roese
125633fa0e7SStefan Roese /* Enable VBUS power: Set output value of VBUS pin as enabled */
126633fa0e7SStefan Roese buf[0] |= I2C_IO_REG_VBUS;
127633fa0e7SStefan Roese ret = dm_i2c_write(dev, I2C_IO_DATA_OUT_REG_0, buf, 1);
128633fa0e7SStefan Roese if (ret) {
129633fa0e7SStefan Roese printf("Failed to set IO expander via I2C\n");
130633fa0e7SStefan Roese return -EIO;
131633fa0e7SStefan Roese }
132633fa0e7SStefan Roese
133633fa0e7SStefan Roese mdelay(500); /* required delay to let output value settle */
134633fa0e7SStefan Roese usb_enabled = 1;
135acd3b076SStefan Roese }
136633fa0e7SStefan Roese
137633fa0e7SStefan Roese return 0;
138633fa0e7SStefan Roese }
139633fa0e7SStefan Roese
board_early_init_f(void)140633fa0e7SStefan Roese int board_early_init_f(void)
141633fa0e7SStefan Roese {
142633fa0e7SStefan Roese /* Nothing to do (yet), perhaps later some pin-muxing etc */
143633fa0e7SStefan Roese
144633fa0e7SStefan Roese return 0;
145633fa0e7SStefan Roese }
146633fa0e7SStefan Roese
board_init(void)147633fa0e7SStefan Roese int board_init(void)
148633fa0e7SStefan Roese {
149633fa0e7SStefan Roese /* adress of boot parameters */
150633fa0e7SStefan Roese gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100;
151633fa0e7SStefan Roese
152633fa0e7SStefan Roese return 0;
153633fa0e7SStefan Roese }
154633fa0e7SStefan Roese
board_late_init(void)155633fa0e7SStefan Roese int board_late_init(void)
156633fa0e7SStefan Roese {
157633fa0e7SStefan Roese /* Pre-configure the USB ports (overcurrent, VBus) */
158633fa0e7SStefan Roese board_xhci_config();
159633fa0e7SStefan Roese
160633fa0e7SStefan Roese return 0;
161633fa0e7SStefan Roese }
162