blob: 60b00246307888d3e64440a1ee9510614470a52b [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Stefan Roese7be1b9b2016-05-25 08:21:21 +02002/*
3 * Copyright (C) 2016 Stefan Roese <sr@denx.de>
Stefan Roese7be1b9b2016-05-25 08:21:21 +02004 */
5
6#include <common.h>
Stefan Roeseb961b862016-10-25 12:41:45 +02007#include <dm.h>
Stefan Roese7be1b9b2016-05-25 08:21:21 +02008#include <i2c.h>
Simon Glassa7b51302019-11-14 12:57:46 -07009#include <init.h>
Stefan Roese7be1b9b2016-05-25 08:21:21 +020010#include <asm/io.h>
11#include <asm/arch/cpu.h>
12#include <asm/arch/soc.h>
Simon Glassdbd79542020-05-10 11:40:11 -060013#include <linux/delay.h>
Stefan Roese7be1b9b2016-05-25 08:21:21 +020014
15DECLARE_GLOBAL_DATA_PTR;
16
Stefan Roeseb961b862016-10-25 12:41:45 +020017/*
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 */
Stefan Roese7be1b9b2016-05-25 08:21:21 +020022/* 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
37static 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 */
48int board_xhci_config(void)
49{
50 struct udevice *dev;
51 int ret;
52 u8 buf[8];
53
Stefan Roeseb961b862016-10-25 12:41:45 +020054 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 }
Stefan Roese7be1b9b2016-05-25 08:21:21 +020061
Stefan Roeseb961b862016-10-25 12:41:45 +020062 /*
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 }
Stefan Roese7be1b9b2016-05-25 08:21:21 +020078
Stefan Roeseb961b862016-10-25 12:41:45 +020079 /* 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 }
Stefan Roese7be1b9b2016-05-25 08:21:21 +020092
Stefan Roeseb961b862016-10-25 12:41:45 +020093 mdelay(500); /* required delay to let output value settle */
94 }
Stefan Roese7be1b9b2016-05-25 08:21:21 +020095
96 return 0;
97}
98
Jon Nettletona81f47c2017-11-06 10:33:19 +020099int board_xhci_enable(fdt_addr_t base)
Stefan Roese7be1b9b2016-05-25 08:21:21 +0200100{
101 struct udevice *dev;
102 int ret;
103 u8 buf[8];
104
Stefan Roeseb961b862016-10-25 12:41:45 +0200105 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;
Stefan Roese7be1b9b2016-05-25 08:21:21 +0200112
Stefan Roeseb961b862016-10-25 12:41:45 +0200113 /* 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 }
Stefan Roese7be1b9b2016-05-25 08:21:21 +0200119
Stefan Roeseb961b862016-10-25 12:41:45 +0200120 /* 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 }
Stefan Roese7be1b9b2016-05-25 08:21:21 +0200126
Stefan Roeseb961b862016-10-25 12:41:45 +0200127 /* 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 }
Stefan Roese7be1b9b2016-05-25 08:21:21 +0200134
Stefan Roeseb961b862016-10-25 12:41:45 +0200135 mdelay(500); /* required delay to let output value settle */
136 usb_enabled = 1;
137 }
Stefan Roese7be1b9b2016-05-25 08:21:21 +0200138
139 return 0;
140}
141
142int board_early_init_f(void)
143{
144 /* Nothing to do (yet), perhaps later some pin-muxing etc */
145
146 return 0;
147}
148
149int 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
157int board_late_init(void)
158{
159 /* Pre-configure the USB ports (overcurrent, VBus) */
160 board_xhci_config();
161
162 return 0;
163}