blob: f4eabfb14f1dacb6a0600fc04ab00e025d0806da [file] [log] [blame]
Stefan Roese7be1b9b2016-05-25 08:21:21 +02001/*
2 * Copyright (C) 2016 Stefan Roese <sr@denx.de>
3 *
4 * SPDX-License-Identifier: GPL-2.0+
5 */
6
7#include <common.h>
Stefan Roeseb961b862016-10-25 12:41:45 +02008#include <dm.h>
Stefan Roese7be1b9b2016-05-25 08:21:21 +02009#include <i2c.h>
10#include <asm/io.h>
11#include <asm/arch/cpu.h>
12#include <asm/arch/soc.h>
13
14DECLARE_GLOBAL_DATA_PTR;
15
Stefan Roeseb961b862016-10-25 12:41:45 +020016/*
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 */
Stefan Roese7be1b9b2016-05-25 08:21:21 +020021/* 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
36static 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 */
47int board_xhci_config(void)
48{
49 struct udevice *dev;
50 int ret;
51 u8 buf[8];
52
Stefan Roeseb961b862016-10-25 12:41:45 +020053 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 }
Stefan Roese7be1b9b2016-05-25 08:21:21 +020060
Stefan Roeseb961b862016-10-25 12:41:45 +020061 /*
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 }
Stefan Roese7be1b9b2016-05-25 08:21:21 +020077
Stefan Roeseb961b862016-10-25 12:41:45 +020078 /* 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 }
Stefan Roese7be1b9b2016-05-25 08:21:21 +020091
Stefan Roeseb961b862016-10-25 12:41:45 +020092 mdelay(500); /* required delay to let output value settle */
93 }
Stefan Roese7be1b9b2016-05-25 08:21:21 +020094
95 return 0;
96}
97
Jon Nettletona81f47c2017-11-06 10:33:19 +020098int board_xhci_enable(fdt_addr_t base)
Stefan Roese7be1b9b2016-05-25 08:21:21 +020099{
100 struct udevice *dev;
101 int ret;
102 u8 buf[8];
103
Stefan Roeseb961b862016-10-25 12:41:45 +0200104 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;
Stefan Roese7be1b9b2016-05-25 08:21:21 +0200111
Stefan Roeseb961b862016-10-25 12:41:45 +0200112 /* 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 }
Stefan Roese7be1b9b2016-05-25 08:21:21 +0200118
Stefan Roeseb961b862016-10-25 12:41:45 +0200119 /* 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 }
Stefan Roese7be1b9b2016-05-25 08:21:21 +0200125
Stefan Roeseb961b862016-10-25 12:41:45 +0200126 /* 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 }
Stefan Roese7be1b9b2016-05-25 08:21:21 +0200133
Stefan Roeseb961b862016-10-25 12:41:45 +0200134 mdelay(500); /* required delay to let output value settle */
135 usb_enabled = 1;
136 }
Stefan Roese7be1b9b2016-05-25 08:21:21 +0200137
138 return 0;
139}
140
141int board_early_init_f(void)
142{
143 /* Nothing to do (yet), perhaps later some pin-muxing etc */
144
145 return 0;
146}
147
148int 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
156int board_late_init(void)
157{
158 /* Pre-configure the USB ports (overcurrent, VBus) */
159 board_xhci_config();
160
161 return 0;
162}