40cc2a854eeea55fc51bbd1ef6c821ba90c6f906
[oweals/u-boot.git] / board / dhelectronics / dh_imx6 / dh_imx6.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * DHCOM DH-iMX6 PDK board support
4  *
5  * Copyright (C) 2017 Marek Vasut <marex@denx.de>
6  */
7
8 #include <common.h>
9 #include <dm.h>
10 #include <dm/device-internal.h>
11 #include <asm/arch/clock.h>
12 #include <asm/arch/crm_regs.h>
13 #include <asm/arch/imx-regs.h>
14 #include <asm/arch/iomux.h>
15 #include <asm/arch/mx6-pins.h>
16 #include <asm/arch/sys_proto.h>
17 #include <asm/gpio.h>
18 #include <asm/io.h>
19 #include <asm/mach-imx/boot_mode.h>
20 #include <asm/mach-imx/iomux-v3.h>
21 #include <asm/mach-imx/sata.h>
22 #include <ahci.h>
23 #include <dwc_ahsata.h>
24 #include <environment.h>
25 #include <errno.h>
26 #include <fsl_esdhc_imx.h>
27 #include <fuse.h>
28 #include <i2c_eeprom.h>
29 #include <miiphy.h>
30 #include <mmc.h>
31 #include <net.h>
32 #include <netdev.h>
33 #include <usb.h>
34 #include <usb/ehci-ci.h>
35
36 DECLARE_GLOBAL_DATA_PTR;
37
38 int dram_init(void)
39 {
40         gd->ram_size = imx_ddr_size();
41         return 0;
42 }
43
44 /*
45  * Do not overwrite the console
46  * Use always serial for U-Boot console
47  */
48 int overwrite_console(void)
49 {
50         return 1;
51 }
52
53 #ifdef CONFIG_FEC_MXC
54 static void eth_phy_reset(void)
55 {
56         /* Reset PHY */
57         gpio_direction_output(IMX_GPIO_NR(5, 0) , 0);
58         udelay(500);
59         gpio_set_value(IMX_GPIO_NR(5, 0), 1);
60
61         /* Enable VIO */
62         gpio_direction_output(IMX_GPIO_NR(1, 7) , 0);
63
64         /*
65          * KSZ9021 PHY needs at least 10 mSec after PHY reset
66          * is released to stabilize
67          */
68         mdelay(10);
69 }
70
71 static int setup_fec_clock(void)
72 {
73         struct iomuxc *iomuxc_regs = (struct iomuxc *)IOMUXC_BASE_ADDR;
74
75         /* set gpr1[21] to select anatop clock */
76         clrsetbits_le32(&iomuxc_regs->gpr[1], 0x1 << 21, 0x1 << 21);
77
78         return enable_fec_anatop_clock(0, ENET_50MHZ);
79 }
80
81 int board_eth_init(bd_t *bis)
82 {
83         uint32_t base = IMX_FEC_BASE;
84         struct mii_dev *bus = NULL;
85         struct phy_device *phydev = NULL;
86
87         gpio_request(IMX_GPIO_NR(5, 0), "PHY-reset");
88         gpio_request(IMX_GPIO_NR(1, 7), "VIO");
89
90         setup_fec_clock();
91
92         eth_phy_reset();
93
94         bus = fec_get_miibus(base, -1);
95         if (!bus)
96                 return -EINVAL;
97
98         /* Scan PHY 0 */
99         phydev = phy_find_by_mask(bus, 0xf, PHY_INTERFACE_MODE_RGMII);
100         if (!phydev) {
101                 printf("Ethernet PHY not found!\n");
102                 return -EINVAL;
103         }
104
105         return fec_probe(bis, -1, base, bus, phydev);
106 }
107 #endif
108
109 #ifdef CONFIG_USB_EHCI_MX6
110 static void setup_usb(void)
111 {
112         /*
113          * Set daisy chain for otg_pin_id on MX6Q.
114          * For MX6DL, this bit is reserved.
115          */
116         imx_iomux_set_gpr_register(1, 13, 1, 0);
117 }
118
119 int board_usb_phy_mode(int port)
120 {
121         if (port == 1)
122                 return USB_INIT_HOST;
123         else
124                 return USB_INIT_DEVICE;
125 }
126 #endif
127
128 static int setup_dhcom_mac_from_fuse(void)
129 {
130         struct udevice *dev;
131         ofnode eeprom;
132         unsigned char enetaddr[6];
133         int ret;
134
135         ret = eth_env_get_enetaddr("ethaddr", enetaddr);
136         if (ret)        /* ethaddr is already set */
137                 return 0;
138
139         imx_get_mac_from_fuse(0, enetaddr);
140
141         if (is_valid_ethaddr(enetaddr)) {
142                 eth_env_set_enetaddr("ethaddr", enetaddr);
143                 return 0;
144         }
145
146         eeprom = ofnode_path("/soc/aips-bus@2100000/i2c@21a8000/eeprom@50");
147         if (!ofnode_valid(eeprom)) {
148                 printf("Invalid hardware path to EEPROM!\n");
149                 return -ENODEV;
150         }
151
152         ret = uclass_get_device_by_ofnode(UCLASS_I2C_EEPROM, eeprom, &dev);
153         if (ret) {
154                 printf("Cannot find EEPROM!\n");
155                 return ret;
156         }
157
158         ret = i2c_eeprom_read(dev, 0xfa, enetaddr, 0x6);
159         if (ret) {
160                 printf("Error reading configuration EEPROM!\n");
161                 return ret;
162         }
163
164         if (is_valid_ethaddr(enetaddr))
165                 eth_env_set_enetaddr("ethaddr", enetaddr);
166
167         return 0;
168 }
169
170 int board_early_init_f(void)
171 {
172 #ifdef CONFIG_USB_EHCI_MX6
173         setup_usb();
174 #endif
175
176         return 0;
177 }
178
179 int board_init(void)
180 {
181         struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
182
183         /* address of boot parameters */
184         gd->bd->bi_boot_params = PHYS_SDRAM + 0x100;
185
186         /* Enable eim_slow clocks */
187         setbits_le32(&mxc_ccm->CCGR6, 0x1 << MXC_CCM_CCGR6_EMI_SLOW_OFFSET);
188
189         setup_dhcom_mac_from_fuse();
190
191         return 0;
192 }
193
194 #ifdef CONFIG_CMD_BMODE
195 static const struct boot_mode board_boot_modes[] = {
196         /* 4 bit bus width */
197         {"sd2",  MAKE_CFGVAL(0x40, 0x28, 0x00, 0x00)},
198         {"sd3",  MAKE_CFGVAL(0x40, 0x30, 0x00, 0x00)},
199         /* 8 bit bus width */
200         {"emmc", MAKE_CFGVAL(0x40, 0x38, 0x00, 0x00)},
201         {NULL,   0},
202 };
203 #endif
204
205 #define HW_CODE_BIT_0   IMX_GPIO_NR(2, 19)
206 #define HW_CODE_BIT_1   IMX_GPIO_NR(6, 6)
207 #define HW_CODE_BIT_2   IMX_GPIO_NR(2, 16)
208
209 static int board_get_hwcode(void)
210 {
211         int hw_code;
212
213         gpio_request(HW_CODE_BIT_0, "HW-code-bit-0");
214         gpio_request(HW_CODE_BIT_1, "HW-code-bit-1");
215         gpio_request(HW_CODE_BIT_2, "HW-code-bit-2");
216
217         gpio_direction_input(HW_CODE_BIT_0);
218         gpio_direction_input(HW_CODE_BIT_1);
219         gpio_direction_input(HW_CODE_BIT_2);
220
221         /* HW 100 + HW 200 = 00b; HW 300 = 01b */
222         hw_code = ((gpio_get_value(HW_CODE_BIT_2) << 2) |
223                    (gpio_get_value(HW_CODE_BIT_1) << 1) |
224                     gpio_get_value(HW_CODE_BIT_0)) + 2;
225
226         return hw_code;
227 }
228
229 int board_late_init(void)
230 {
231         u32 hw_code;
232         char buf[16];
233
234         hw_code = board_get_hwcode();
235
236         switch (get_cpu_type()) {
237         case MXC_CPU_MX6SOLO:
238                 snprintf(buf, sizeof(buf), "imx6s-dhcom%1d", hw_code);
239                 break;
240         case MXC_CPU_MX6DL:
241                 snprintf(buf, sizeof(buf), "imx6dl-dhcom%1d", hw_code);
242                 break;
243         case MXC_CPU_MX6D:
244                 snprintf(buf, sizeof(buf), "imx6d-dhcom%1d", hw_code);
245                 break;
246         case MXC_CPU_MX6Q:
247                 snprintf(buf, sizeof(buf), "imx6q-dhcom%1d", hw_code);
248                 break;
249         default:
250                 snprintf(buf, sizeof(buf), "UNKNOWN%1d", hw_code);
251                 break;
252         }
253
254         env_set("dhcom", buf);
255
256 #ifdef CONFIG_CMD_BMODE
257         add_board_boot_modes(board_boot_modes);
258 #endif
259         return 0;
260 }
261
262 int checkboard(void)
263 {
264         puts("Board: DHCOM i.MX6\n");
265         return 0;
266 }
267
268 #ifdef CONFIG_MULTI_DTB_FIT
269 int board_fit_config_name_match(const char *name)
270 {
271         if (is_mx6dq()) {
272                 if (!strcmp(name, "imx6q-dhcom-pdk2"))
273                         return 0;
274         } else if (is_mx6sdl()) {
275                 if (!strcmp(name, "imx6dl-dhcom-pdk2"))
276                         return 0;
277         }
278
279         return -1;
280 }
281 #endif