blob: 3337f3fbe756e4cb600e444ccb325baf03a89919 [file] [log] [blame]
Stefan Roese6edf27e2016-05-17 15:04:16 +02001/*
2 * Copyright (C) 2016 Stefan Roese <sr@denx.de>
3 *
4 * SPDX-License-Identifier: GPL-2.0+
5 */
6
7#include <common.h>
8#include <i2c.h>
9#include <asm/io.h>
10#include <asm/arch/cpu.h>
11#include <asm/arch/soc.h>
12
13DECLARE_GLOBAL_DATA_PTR;
14
15/* IO expander I2C device */
16#define I2C_IO_EXP_ADDR 0x22
17#define I2C_IO_CFG_REG_0 0x6
18#define I2C_IO_DATA_OUT_REG_0 0x2
19#define I2C_IO_REG_0_SATA_OFF 2
20#define I2C_IO_REG_0_USB_H_OFF 1
21
Konstantin Porotchkincfa88a32017-02-16 13:52:26 +020022#define PINCTRL_NB_REG_VALUE 0x000173fa
23#define PINCTRL_SB_REG_VALUE 0x00007a23
24
Stefan Roese6edf27e2016-05-17 15:04:16 +020025int board_early_init_f(void)
26{
Konstantin Porotchkincfa88a32017-02-16 13:52:26 +020027 const void *blob = gd->fdt_blob;
28 const char *bank_name;
29 const char *compat = "marvell,armada-3700-pinctl";
30 int off, len;
31 void __iomem *addr;
32
33 /* FIXME
34 * Temporary WA for setting correct pin control values
35 * until the real pin control driver is awailable.
36 */
37 off = fdt_node_offset_by_compatible(blob, -1, compat);
38 while (off != -FDT_ERR_NOTFOUND) {
39 bank_name = fdt_getprop(blob, off, "bank-name", &len);
40 addr = (void __iomem *)fdtdec_get_addr_size_auto_noparent(
41 blob, off, "reg", 0, NULL, true);
42 if (!strncmp(bank_name, "armada-3700-nb", len))
43 writel(PINCTRL_NB_REG_VALUE, addr);
44 else if (!strncmp(bank_name, "armada-3700-sb", len))
45 writel(PINCTRL_SB_REG_VALUE, addr);
46
47 off = fdt_node_offset_by_compatible(blob, off, compat);
48 }
Stefan Roese6edf27e2016-05-17 15:04:16 +020049
50 return 0;
51}
52
53int board_init(void)
54{
55 /* adress of boot parameters */
56 gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100;
57
58 return 0;
59}
60
61/* Board specific AHCI / SATA enable code */
62int board_ahci_enable(void)
63{
64 struct udevice *dev;
65 int ret;
66 u8 buf[8];
67
68 /* Configure IO exander PCA9555: 7bit address 0x22 */
69 ret = i2c_get_chip_for_busnum(0, I2C_IO_EXP_ADDR, 1, &dev);
70 if (ret) {
71 printf("Cannot find PCA9555: %d\n", ret);
72 return 0;
73 }
74
75 ret = dm_i2c_read(dev, I2C_IO_CFG_REG_0, buf, 1);
76 if (ret) {
77 printf("Failed to read IO expander value via I2C\n");
78 return -EIO;
79 }
80
81 /*
82 * Enable SATA power via IO expander connected via I2C by setting
83 * the corresponding bit to output mode to enable power for SATA
84 */
85 buf[0] &= ~(1 << I2C_IO_REG_0_SATA_OFF);
86 ret = dm_i2c_write(dev, I2C_IO_CFG_REG_0, buf, 1);
87 if (ret) {
88 printf("Failed to set IO expander via I2C\n");
89 return -EIO;
90 }
91
92 return 0;
93}
94
95/* Board specific xHCI enable code */
96int board_xhci_enable(void)
97{
98 struct udevice *dev;
99 int ret;
100 u8 buf[8];
101
102 /* Configure IO exander PCA9555: 7bit address 0x22 */
103 ret = i2c_get_chip_for_busnum(0, I2C_IO_EXP_ADDR, 1, &dev);
104 if (ret) {
105 printf("Cannot find PCA9555: %d\n", ret);
106 return 0;
107 }
108
109 printf("Enable USB VBUS\n");
110
111 /*
112 * Read configuration (direction) and set VBUS pin as output
113 * (reset pin = output)
114 */
115 ret = dm_i2c_read(dev, I2C_IO_CFG_REG_0, buf, 1);
116 if (ret) {
117 printf("Failed to read IO expander value via I2C\n");
118 return -EIO;
119 }
120 buf[0] &= ~(1 << I2C_IO_REG_0_USB_H_OFF);
121 ret = dm_i2c_write(dev, I2C_IO_CFG_REG_0, buf, 1);
122 if (ret) {
123 printf("Failed to set IO expander via I2C\n");
124 return -EIO;
125 }
126
127 /* Read VBUS output value and disable it */
128 ret = dm_i2c_read(dev, I2C_IO_DATA_OUT_REG_0, buf, 1);
129 if (ret) {
130 printf("Failed to read IO expander value via I2C\n");
131 return -EIO;
132 }
133 buf[0] &= ~(1 << I2C_IO_REG_0_USB_H_OFF);
134 ret = dm_i2c_write(dev, I2C_IO_DATA_OUT_REG_0, buf, 1);
135 if (ret) {
136 printf("Failed to set IO expander via I2C\n");
137 return -EIO;
138 }
139
140 /*
141 * Required delay for configuration to settle - must wait for
142 * power on port is disabled in case VBUS signal was high,
143 * required 3 seconds delay to let VBUS signal fully settle down
144 */
145 mdelay(3000);
146
147 /* Enable VBUS power: Set output value of VBUS pin as enabled */
148 buf[0] |= (1 << I2C_IO_REG_0_USB_H_OFF);
149 ret = dm_i2c_write(dev, I2C_IO_DATA_OUT_REG_0, buf, 1);
150 if (ret) {
151 printf("Failed to set IO expander via I2C\n");
152 return -EIO;
153 }
154
155 mdelay(500); /* required delay to let output value settle */
156
157 return 0;
158}