spi: zynqmp_gqspi: fix set_speed bug on multiple runs
[platform/kernel/u-boot.git] / board / amlogic / vim3 / vim3.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2020 BayLibre, SAS
4  * Author: Neil Armstrong <narmstrong@baylibre.com>
5  */
6
7 #include <common.h>
8 #include <dm.h>
9 #include <env_internal.h>
10 #include <init.h>
11 #include <net.h>
12 #include <asm/io.h>
13 #include <asm/arch/boot.h>
14 #include <asm/arch/eth.h>
15 #include <asm/arch/sm.h>
16 #include <i2c.h>
17 #include "khadas-mcu.h"
18
19 int mmc_get_env_dev(void)
20 {
21         if (meson_get_boot_device() == BOOT_DEVICE_EMMC)
22                 return 2;
23         return 1;
24 }
25
26 /*
27  * The VIM3 on-board  MCU can mux the PCIe/USB3.0 shared differential
28  * lines using a FUSB340TMX USB 3.1 SuperSpeed Data Switch between
29  * an USB3.0 Type A connector and a M.2 Key M slot.
30  * The PHY driving these differential lines is shared between
31  * the USB3.0 controller and the PCIe Controller, thus only
32  * a single controller can use it.
33  */
34 int meson_ft_board_setup(void *blob, struct bd_info *bd)
35 {
36         struct udevice *bus, *dev;
37         int node, i2c_node, ret;
38         unsigned int i2c_addr;
39         u32 *val;
40
41         /* Find I2C device */
42         node = fdt_node_offset_by_compatible(gd->fdt_blob, -1, "khadas,mcu");
43         if (node < 0) {
44                 printf("vim3: cannot find khadas,mcu node\n");
45                 return 0;
46         }
47
48         /* Get addr */
49         val = (u32 *)fdt_getprop(gd->fdt_blob, node, "reg", NULL);
50         if (!val) {
51                 printf("vim3: cannot find khadas,mcu node i2c addr\n");
52                 return 0;
53         }
54         i2c_addr = fdt32_to_cpu(*val);
55
56         /* Get i2c device */
57         i2c_node = fdt_parent_offset(gd->fdt_blob, node);
58         if (node < 0) {
59                 printf("vim3: cannot find khadas,mcu i2c node\n");
60                 return 0;
61         }
62
63         ret = uclass_get_device_by_of_offset(UCLASS_I2C, i2c_node, &bus);
64         if (ret < 0) {
65                 printf("vim3: cannot find i2c bus (%d)\n", ret);
66                 return 0;
67         }
68
69         ret = i2c_get_chip(bus, i2c_addr, 1, &dev);
70         if (ret < 0) {
71                 printf("vim3: cannot find i2c chip (%d)\n", ret);
72                 return 0;
73         }
74
75         /* Read USB_PCIE_SWITCH_REG */
76         ret = dm_i2c_reg_read(dev, KHADAS_MCU_USB_PCIE_SWITCH_REG);
77         if (ret < 0) {
78                 printf("vim3: failed to read i2c reg (%d)\n", ret);
79                 return 0;
80         }
81         debug("MCU_USB_PCIE_SWITCH_REG: %d\n", ret);
82
83         /*
84          * If in PCIe mode, alter DT
85          * 0:Enable USB3.0,Disable PCIE, 1:Disable USB3.0, Enable PCIE
86          */
87         if (ret > 0) {
88                 static char data[32] __aligned(4);
89                 const void *ptmp;
90                 int len;
91
92                 /* Find USB node */
93                 node = fdt_node_offset_by_compatible(blob, -1, "amlogic,meson-g12a-usb-ctrl");
94                 if (node < 0) {
95                         printf("vim3: cannot find amlogic,meson-g12a-usb-ctrl node\n");
96                         return 0;
97                 }
98
99                 /* Update PHY names (mandatory to disable USB3.0) */
100                 len = strlcpy(data, "usb2-phy0", 32) + 1;
101                 len += strlcpy(&data[len], "usb2-phy1", 32 - len) + 1;
102                 ret = fdt_setprop(blob, node, "phy-names", data, len);
103                 if (ret < 0) {
104                         printf("vim3: failed to update usb phy names property (%d)\n", ret);
105                         return 0;
106                 }
107
108                 /* Update PHY list, by keeping the 2 first entries (optional) */
109                 ptmp = fdt_getprop(blob, node, "phys", &len);
110                 if (ptmp) {
111                         memcpy(data, ptmp, min_t(unsigned int, 2 * sizeof(u32), len));
112
113                         ret = fdt_setprop(blob, node, "phys", data,
114                                           min_t(unsigned int, 2 * sizeof(u32), len));
115                         if (ret < 0)
116                                 printf("vim3: failed to update usb phys property (%d)\n", ret);
117                 } else
118                         printf("vim3: cannot find usb node phys property\n");
119
120                 /* Find PCIe node */
121                 node = fdt_node_offset_by_compatible(blob, -1, "amlogic,g12a-pcie");
122                 if (node < 0) {
123                         printf("vim3: cannot find amlogic,g12a-pcie node\n");
124                         return 0;
125                 }
126
127                 /* Enable PCIe */
128                 len = strlcpy(data, "okay", 32);
129                 ret = fdt_setprop(blob, node, "status", data, len);
130                 if (ret < 0) {
131                         printf("vim3: failed to enable pcie node (%d)\n", ret);
132                         return 0;
133                 }
134
135                 printf("vim3: successfully enabled PCIe\n");
136         }
137
138         return 0;
139 }
140
141 #define EFUSE_MAC_OFFSET        0
142 #define EFUSE_MAC_SIZE          12
143 #define MAC_ADDR_LEN            6
144
145 int misc_init_r(void)
146 {
147         u8 mac_addr[MAC_ADDR_LEN];
148         char efuse_mac_addr[EFUSE_MAC_SIZE], tmp[3];
149         ssize_t len;
150
151         meson_eth_init(PHY_INTERFACE_MODE_RGMII, 0);
152
153         if (!eth_env_get_enetaddr("ethaddr", mac_addr)) {
154                 len = meson_sm_read_efuse(EFUSE_MAC_OFFSET,
155                                           efuse_mac_addr, EFUSE_MAC_SIZE);
156                 if (len != EFUSE_MAC_SIZE)
157                         return 0;
158
159                 /* MAC is stored in ASCII format, 1bytes = 2characters */
160                 for (int i = 0; i < 6; i++) {
161                         tmp[0] = efuse_mac_addr[i * 2];
162                         tmp[1] = efuse_mac_addr[i * 2 + 1];
163                         tmp[2] = '\0';
164                         mac_addr[i] = simple_strtoul(tmp, NULL, 16);
165                 }
166
167                 if (is_valid_ethaddr(mac_addr))
168                         eth_env_set_enetaddr("ethaddr", mac_addr);
169                 else
170                         meson_generate_serial_ethaddr();
171
172                 eth_env_get_enetaddr("ethaddr", mac_addr);
173         }
174
175         return 0;
176 }