e97efc1dc337108b00174bc1b38799cf3db9a8e0
[oweals/u-boot.git] / board / compulab / cl-som-imx7 / cl-som-imx7.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * U-Boot board functions for CompuLab CL-SOM-iMX7 module
4  *
5  * (C) Copyright 2017 CompuLab, Ltd. http://www.compulab.com
6  *
7  * Author: Uri Mashiach <uri.mashiach@compulab.co.il>
8  */
9
10 #include <common.h>
11 #include <env.h>
12 #include <init.h>
13 #include <mmc.h>
14 #include <net.h>
15 #include <phy.h>
16 #include <netdev.h>
17 #include <fsl_esdhc_imx.h>
18 #include <power/pmic.h>
19 #include <power/pfuze3000_pmic.h>
20 #include <asm/mach-imx/mxc_i2c.h>
21 #include <asm/mach-imx/iomux-v3.h>
22 #include <asm/arch-mx7/mx7-pins.h>
23 #include <asm/arch-mx7/sys_proto.h>
24 #include <asm/arch-mx7/clock.h>
25 #include "../common/eeprom.h"
26 #include "common.h"
27
28 DECLARE_GLOBAL_DATA_PTR;
29
30 #ifdef CONFIG_SYS_I2C_MXC
31
32 #define I2C_PAD_CTRL            (PAD_CTL_DSE_3P3V_32OHM | PAD_CTL_SRE_SLOW | \
33                                 PAD_CTL_HYS)
34
35 #define CL_SOM_IMX7_GPIO_I2C2_SCL       IMX_GPIO_NR(1, 6)
36 #define CL_SOM_IMX7_GPIO_I2C2_SDA       IMX_GPIO_NR(1, 7)
37
38 static struct i2c_pads_info cl_som_imx7_i2c_pad_info2 = {
39         .scl = {
40                 .i2c_mode = MX7D_PAD_GPIO1_IO06__I2C2_SCL |
41                         MUX_PAD_CTRL(I2C_PAD_CTRL),
42                 .gpio_mode = MX7D_PAD_GPIO1_IO06__GPIO1_IO6 |
43                         MUX_PAD_CTRL(I2C_PAD_CTRL),
44                 .gp = CL_SOM_IMX7_GPIO_I2C2_SCL,
45         },
46         .sda = {
47                 .i2c_mode = MX7D_PAD_GPIO1_IO07__I2C2_SDA |
48                         MUX_PAD_CTRL(I2C_PAD_CTRL),
49                 .gpio_mode = MX7D_PAD_GPIO1_IO07__GPIO1_IO7 |
50                         MUX_PAD_CTRL(I2C_PAD_CTRL),
51                 .gp = CL_SOM_IMX7_GPIO_I2C2_SDA,
52         },
53 };
54
55 /*
56  * cl_som_imx7_setup_i2c() - I2C  pinmux configuration.
57  */
58 static void cl_som_imx7_setup_i2c(void)
59 {
60         setup_i2c(0, CONFIG_SYS_I2C_SPEED, 0x7f, &cl_som_imx7_i2c_pad_info2);
61 }
62 #else /* !CONFIG_SYS_I2C_MXC */
63 static void cl_som_imx7_setup_i2c(void) {}
64 #endif /* CONFIG_SYS_I2C_MXC */
65
66 int dram_init(void)
67 {
68         gd->ram_size = imx_ddr_size();
69
70         return 0;
71 }
72
73 #ifdef CONFIG_FSL_ESDHC_IMX
74
75 #define CL_SOM_IMX7_GPIO_USDHC3_PWR     IMX_GPIO_NR(6, 11)
76
77 static struct fsl_esdhc_cfg cl_som_imx7_usdhc_cfg[3] = {
78         {USDHC1_BASE_ADDR, 0, 4},
79         {USDHC3_BASE_ADDR},
80 };
81
82 int board_mmc_init(bd_t *bis)
83 {
84         int i, ret;
85         /*
86          * According to the board_mmc_init() the following map is done:
87          * (U-boot device node)    (Physical Port)
88          * mmc0                    USDHC1
89          * mmc2                    USDHC3 (eMMC)
90          */
91         for (i = 0; i < CONFIG_SYS_FSL_USDHC_NUM; i++) {
92                 switch (i) {
93                 case 0:
94                         cl_som_imx7_usdhc1_pads_set();
95                         gpio_request(CL_SOM_IMX7_GPIO_USDHC1_CD, "usdhc1_cd");
96                         cl_som_imx7_usdhc_cfg[0].sdhc_clk =
97                                 mxc_get_clock(MXC_ESDHC_CLK);
98                         break;
99                 case 1:
100                         cl_som_imx7_usdhc3_emmc_pads_set();
101                         gpio_request(CL_SOM_IMX7_GPIO_USDHC3_PWR, "usdhc3_pwr");
102                         gpio_direction_output(CL_SOM_IMX7_GPIO_USDHC3_PWR, 0);
103                         udelay(500);
104                         gpio_direction_output(CL_SOM_IMX7_GPIO_USDHC3_PWR, 1);
105                         cl_som_imx7_usdhc_cfg[1].sdhc_clk =
106                                 mxc_get_clock(MXC_ESDHC3_CLK);
107                         break;
108                 default:
109                         printf("Warning: you configured more USDHC controllers "
110                                 "(%d) than supported by the board\n", i + 1);
111                         return -EINVAL;
112                 }
113
114                 ret = fsl_esdhc_initialize(bis, &cl_som_imx7_usdhc_cfg[i]);
115                 if (ret)
116                         return ret;
117         }
118
119         return 0;
120 }
121 #endif /* CONFIG_FSL_ESDHC_IMX */
122
123 #ifdef CONFIG_FEC_MXC
124
125 #define CL_SOM_IMX7_ETH1_PHY_NRST       IMX_GPIO_NR(1, 4)
126
127 /*
128  * cl_som_imx7_rgmii_rework() - Ethernet PHY configuration.
129  */
130 static void cl_som_imx7_rgmii_rework(struct phy_device *phydev)
131 {
132         unsigned short val;
133
134         /* Ar8031 phy SmartEEE feature cause link status generates glitch,
135          * which cause ethernet link down/up issue, so disable SmartEEE
136          */
137         phy_write(phydev, MDIO_DEVAD_NONE, 0xd, 0x3);
138         phy_write(phydev, MDIO_DEVAD_NONE, 0xe, 0x805d);
139         phy_write(phydev, MDIO_DEVAD_NONE, 0xd, 0x4003);
140         val = phy_read(phydev, MDIO_DEVAD_NONE, 0xe);
141         val &= ~(0x1 << 8);
142         phy_write(phydev, MDIO_DEVAD_NONE, 0xe, val);
143
144         /* To enable AR8031 ouput a 125MHz clk from CLK_25M */
145         phy_write(phydev, MDIO_DEVAD_NONE, 0xd, 0x7);
146         phy_write(phydev, MDIO_DEVAD_NONE, 0xe, 0x8016);
147         phy_write(phydev, MDIO_DEVAD_NONE, 0xd, 0x4007);
148
149         val = phy_read(phydev, MDIO_DEVAD_NONE, 0xe);
150         val &= 0xffe3;
151         val |= 0x18;
152         phy_write(phydev, MDIO_DEVAD_NONE, 0xe, val);
153
154         /* introduce tx clock delay */
155         phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x5);
156         val = phy_read(phydev, MDIO_DEVAD_NONE, 0x1e);
157         val |= 0x0100;
158         phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, val);
159 }
160
161 int board_phy_config(struct phy_device *phydev)
162 {
163         cl_som_imx7_rgmii_rework(phydev);
164
165         if (phydev->drv->config)
166                 phydev->drv->config(phydev);
167
168         return 0;
169 }
170
171 /*
172  * cl_som_imx7_handle_mac_address() - set Ethernet MAC address environment.
173  *
174  * @env_var: MAC address environment variable
175  * @eeprom_bus: I2C bus of the environment EEPROM
176  *
177  * @return: 0 on success, < 0 on failure
178  */
179 static int cl_som_imx7_handle_mac_address(char *env_var, uint eeprom_bus)
180 {
181         int ret;
182         unsigned char enetaddr[6];
183
184         ret = eth_env_get_enetaddr(env_var, enetaddr);
185         if (ret)
186                 return 0;
187
188         ret = cl_eeprom_read_mac_addr(enetaddr, eeprom_bus);
189         if (ret)
190                 return ret;
191
192         ret = is_valid_ethaddr(enetaddr);
193         if (!ret)
194                 return -1;
195
196         return eth_env_set_enetaddr(env_var, enetaddr);
197 }
198
199 #define CL_SOM_IMX7_FEC_DEV_ID_PRI 0
200
201 int board_eth_init(bd_t *bis)
202 {
203         /* set Ethernet MAC address environment */
204         cl_som_imx7_handle_mac_address("ethaddr", CONFIG_SYS_I2C_EEPROM_BUS);
205         /* Ethernet interface pinmux configuration  */
206         cl_som_imx7_phy1_rst_pads_set();
207         cl_som_imx7_fec1_pads_set();
208         /* PHY reset */
209         gpio_request(CL_SOM_IMX7_ETH1_PHY_NRST, "eth1_phy_nrst");
210         gpio_direction_output(CL_SOM_IMX7_ETH1_PHY_NRST, 0);
211         mdelay(10);
212         gpio_set_value(CL_SOM_IMX7_ETH1_PHY_NRST, 1);
213         /* MAC initialization */
214         return fecmxc_initialize_multi(bis, CL_SOM_IMX7_FEC_DEV_ID_PRI,
215                                        CONFIG_FEC_MXC_PHYADDR, IMX_FEC_BASE);
216 }
217
218 /*
219  * cl_som_imx7_setup_fec() - Ethernet MAC 1 clock configuration.
220  * - ENET1 reference clock mode select.
221  * - ENET1_TX_CLK output driver is disabled when configured for ALT1.
222  */
223 static void cl_som_imx7_setup_fec(void)
224 {
225         struct iomuxc_gpr_base_regs *const iomuxc_gpr_regs
226                 = (struct iomuxc_gpr_base_regs *)IOMUXC_GPR_BASE_ADDR;
227
228         /* Use 125M anatop REF_CLK1 for ENET1, clear gpr1[13], gpr1[17]*/
229         clrsetbits_le32(&iomuxc_gpr_regs->gpr[1],
230                         (IOMUXC_GPR_GPR1_GPR_ENET1_TX_CLK_SEL_MASK |
231                          IOMUXC_GPR_GPR1_GPR_ENET1_CLK_DIR_MASK), 0);
232
233         set_clk_enet(ENET_125MHZ);
234 }
235 #else /* !CONFIG_FEC_MXC */
236 static void cl_som_imx7_setup_fec(void) {}
237 #endif /* CONFIG_FEC_MXC */
238
239 #ifdef CONFIG_SPI
240
241 static void cl_som_imx7_spi_init(void)
242 {
243         cl_som_imx7_espi1_pads_set();
244 }
245 #else /* !CONFIG_SPI */
246 static void cl_som_imx7_spi_init(void) {}
247 #endif /* CONFIG_SPI */
248
249 int board_early_init_f(void)
250 {
251         cl_som_imx7_uart1_pads_set();
252         cl_som_imx7_usb_otg1_pads_set();
253
254         return 0;
255 }
256
257 int board_init(void)
258 {
259         /* address of boot parameters */
260         gd->bd->bi_boot_params = PHYS_SDRAM + 0x100;
261         cl_som_imx7_setup_i2c();
262         cl_som_imx7_setup_fec();
263         cl_som_imx7_spi_init();
264
265         return 0;
266 }
267
268 #ifdef CONFIG_POWER
269 #define I2C_PMIC        0
270 int power_init_board(void)
271 {
272         struct pmic *p;
273         int ret;
274         unsigned int reg, rev_id;
275
276         ret = power_pfuze3000_init(I2C_PMIC);
277         if (ret)
278                 return ret;
279
280         p = pmic_get("PFUZE3000");
281         ret = pmic_probe(p);
282         if (ret)
283                 return ret;
284
285         pmic_reg_read(p, PFUZE3000_DEVICEID, &reg);
286         pmic_reg_read(p, PFUZE3000_REVID, &rev_id);
287         printf("PMIC: PFUZE3000 DEV_ID=0x%x REV_ID=0x%x\n", reg, rev_id);
288
289         /* disable Low Power Mode during standby mode */
290         pmic_reg_write(p, PFUZE3000_LDOGCTL, 0x1);
291
292         return 0;
293 }
294 #endif /* CONFIG_POWER */
295
296 /*
297  * cl_som_imx7_setup_wdog() - watchdog configuration.
298  * - Output WDOG_B signal to reset external pmic.
299  * - Suspend the watchdog timer during low-power modes.
300  */
301 void cl_som_imx7_setup_wdog(void)
302 {
303         struct wdog_regs *wdog = (struct wdog_regs *)WDOG1_BASE_ADDR;
304
305         cl_som_imx7_wdog_pads_set();
306         set_wdog_reset(wdog);
307        /*
308         * Do not assert internal WDOG_RESET_B_DEB(controlled by bit 4),
309         * since we use PMIC_PWRON to reset the board.
310         */
311         clrsetbits_le16(&wdog->wcr, 0, 0x10);
312 }
313
314 int board_late_init(void)
315 {
316         env_set("board_name", "CL-SOM-iMX7");
317         cl_som_imx7_setup_wdog();
318         return 0;
319 }
320
321 int checkboard(void)
322 {
323         char *mode;
324
325         if (IS_ENABLED(CONFIG_ARMV7_BOOT_SEC_DEFAULT))
326                 mode = "secure";
327         else
328                 mode = "non-secure";
329
330         printf("Board: CL-SOM-iMX7 in %s mode\n", mode);
331
332         return 0;
333 }