]> git.sur5r.net Git - u-boot/blob - board/Marvell/mvebu_armada-37xx/board.c
arm64: a37xx: Handle pin controls in early board init
[u-boot] / board / Marvell / mvebu_armada-37xx / board.c
1 /*
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
13 DECLARE_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
22 #define PINCTRL_NB_REG_VALUE    0x000173fa
23 #define PINCTRL_SB_REG_VALUE    0x00007a23
24
25 int board_early_init_f(void)
26 {
27         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         }
49
50         return 0;
51 }
52
53 int 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 */
62 int 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 */
96 int 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 }