blob: af1a3e75cb508c672c6d5d478948c94943327ffc [file] [log] [blame]
Christoph Fritzd1708642016-11-29 16:13:40 +01001/*
2 * Copyright (C) 2016 samtec automotive software & electronics gmbh
3 *
4 * Author: Christoph Fritz <chf.fritz@googlemail.com>
5 *
6 * SPDX-License-Identifier: GPL-2.0+
7 */
8
9#include <asm/arch/clock.h>
10#include <asm/arch/crm_regs.h>
11#include <asm/arch/iomux.h>
12#include <asm/arch/imx-regs.h>
13#include <asm/arch/mx6-pins.h>
14#include <asm/arch/sys_proto.h>
15#include <asm/gpio.h>
Stefano Babic33731bc2017-06-29 10:16:06 +020016#include <asm/mach-imx/iomux-v3.h>
Christoph Fritzd1708642016-11-29 16:13:40 +010017#include <asm/io.h>
Stefano Babic33731bc2017-06-29 10:16:06 +020018#include <asm/mach-imx/mxc_i2c.h>
Christoph Fritzd1708642016-11-29 16:13:40 +010019#include <linux/sizes.h>
20#include <common.h>
21#include <fsl_esdhc.h>
22#include <mmc.h>
23#include <i2c.h>
24#include <miiphy.h>
25#include <netdev.h>
26#include <power/pmic.h>
27#include <power/pfuze100_pmic.h>
28#include <usb.h>
29#include <usb/ehci-ci.h>
30#include <pwm.h>
31#include <wait_bit.h>
32
33DECLARE_GLOBAL_DATA_PTR;
34
35#define UART_PAD_CTRL (PAD_CTL_HYS | PAD_CTL_PUS_100K_UP | \
36 PAD_CTL_PKE | PAD_CTL_SPEED_MED | PAD_CTL_DSE_40ohm | \
37 PAD_CTL_SRE_FAST)
38
39#define ENET_PAD_CTRL (PAD_CTL_PUS_100K_UP | PAD_CTL_PKE | \
40 PAD_CTL_SPEED_HIGH | PAD_CTL_DSE_48ohm | \
41 PAD_CTL_SRE_FAST)
42
43#define ENET_CLK_PAD_CTRL PAD_CTL_DSE_34ohm
44
45#define ENET_RX_PAD_CTRL (PAD_CTL_PKE | \
46 PAD_CTL_PUS_100K_DOWN | PAD_CTL_SPEED_HIGH | \
47 PAD_CTL_SRE_FAST)
48
49#define I2C_PAD_CTRL (PAD_CTL_HYS | PAD_CTL_PUS_100K_UP | \
50 PAD_CTL_PKE | PAD_CTL_ODE | PAD_CTL_SPEED_MED | \
51 PAD_CTL_DSE_40ohm)
52
53#define USDHC_CLK_PAD_CTRL (PAD_CTL_HYS | PAD_CTL_SPEED_MED | \
54 PAD_CTL_DSE_80ohm | PAD_CTL_SRE_FAST)
55
56#define USDHC_PAD_CTRL (PAD_CTL_HYS | PAD_CTL_PUS_47K_UP | \
57 PAD_CTL_PKE | PAD_CTL_SPEED_MED | PAD_CTL_DSE_80ohm | \
58 PAD_CTL_SRE_FAST)
59
60#define GPIO_PAD_CTRL (PAD_CTL_HYS | PAD_CTL_PUS_100K_UP | \
61 PAD_CTL_PKE)
62
63int dram_init(void)
64{
65 gd->ram_size = imx_ddr_size();
66
67 return 0;
68}
69
70static iomux_v3_cfg_t const uart1_pads[] = {
71 MX6_PAD_GPIO1_IO04__UART1_TX | MUX_PAD_CTRL(UART_PAD_CTRL),
72 MX6_PAD_GPIO1_IO05__UART1_RX | MUX_PAD_CTRL(UART_PAD_CTRL),
73};
74
75static iomux_v3_cfg_t const usdhc2_pads[] = {
76 MX6_PAD_SD2_CLK__USDHC2_CLK | MUX_PAD_CTRL(USDHC_CLK_PAD_CTRL),
77 MX6_PAD_SD2_CMD__USDHC2_CMD | MUX_PAD_CTRL(USDHC_PAD_CTRL),
78 MX6_PAD_SD2_DATA0__USDHC2_DATA0 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
79 MX6_PAD_SD2_DATA1__USDHC2_DATA1 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
80 MX6_PAD_SD2_DATA2__USDHC2_DATA2 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
81 MX6_PAD_SD2_DATA3__USDHC2_DATA3 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
82 MX6_PAD_LCD1_VSYNC__GPIO3_IO_28 | MUX_PAD_CTRL(GPIO_PAD_CTRL),
83};
84
85static iomux_v3_cfg_t const usdhc4_pads[] = {
86 MX6_PAD_SD4_CLK__USDHC4_CLK | MUX_PAD_CTRL(USDHC_CLK_PAD_CTRL),
87 MX6_PAD_SD4_CMD__USDHC4_CMD | MUX_PAD_CTRL(USDHC_PAD_CTRL),
88 MX6_PAD_SD4_DATA0__USDHC4_DATA0 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
89 MX6_PAD_SD4_DATA1__USDHC4_DATA1 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
90 MX6_PAD_SD4_DATA2__USDHC4_DATA2 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
91 MX6_PAD_SD4_DATA3__USDHC4_DATA3 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
92 MX6_PAD_SD4_DATA4__USDHC4_DATA4 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
93 MX6_PAD_SD4_DATA5__USDHC4_DATA5 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
94 MX6_PAD_SD4_DATA6__USDHC4_DATA6 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
95 MX6_PAD_SD4_DATA7__USDHC4_DATA7 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
96};
97
98static iomux_v3_cfg_t const fec1_pads[] = {
99 MX6_PAD_ENET1_MDC__ENET1_MDC | MUX_PAD_CTRL(ENET_PAD_CTRL),
100 MX6_PAD_ENET1_MDIO__ENET1_MDIO | MUX_PAD_CTRL(ENET_PAD_CTRL),
101 MX6_PAD_RGMII1_RD0__ENET1_RX_DATA_0 | MUX_PAD_CTRL(ENET_RX_PAD_CTRL),
102 MX6_PAD_RGMII1_RD1__ENET1_RX_DATA_1 | MUX_PAD_CTRL(ENET_RX_PAD_CTRL),
103 MX6_PAD_RGMII1_TD0__ENET1_TX_DATA_0 | MUX_PAD_CTRL(ENET_PAD_CTRL),
104 MX6_PAD_RGMII1_TD1__ENET1_TX_DATA_1 | MUX_PAD_CTRL(ENET_PAD_CTRL),
105 MX6_PAD_RGMII1_RX_CTL__ENET1_RX_EN | MUX_PAD_CTRL(ENET_RX_PAD_CTRL),
106 MX6_PAD_RGMII1_TX_CTL__ENET1_TX_EN | MUX_PAD_CTRL(ENET_PAD_CTRL),
107 MX6_PAD_ENET1_TX_CLK__ENET1_REF_CLK1 | MUX_PAD_CTRL(ENET_CLK_PAD_CTRL) |
108 MUX_MODE_SION,
109 /* LAN8720 PHY Reset */
110 MX6_PAD_RGMII1_TD3__GPIO5_IO_9 | MUX_PAD_CTRL(NO_PAD_CTRL),
111};
112
113static iomux_v3_cfg_t const pwm_led_pads[] = {
114 MX6_PAD_RGMII2_RD2__PWM2_OUT | MUX_PAD_CTRL(NO_PAD_CTRL), /* green */
115 MX6_PAD_RGMII2_TD2__PWM6_OUT | MUX_PAD_CTRL(NO_PAD_CTRL), /* red */
116 MX6_PAD_RGMII2_RD3__PWM1_OUT | MUX_PAD_CTRL(NO_PAD_CTRL), /* blue */
117};
118
119static void setup_iomux_uart(void)
120{
121 imx_iomux_v3_setup_multiple_pads(uart1_pads, ARRAY_SIZE(uart1_pads));
122}
123
124#define PHY_RESET IMX_GPIO_NR(5, 9)
125
126int board_eth_init(bd_t *bis)
127{
128 struct iomuxc *iomuxc_regs = (struct iomuxc *)IOMUXC_BASE_ADDR;
129 int ret;
130 unsigned char eth1addr[6];
131
132 /* just to get secound mac address */
133 imx_get_mac_from_fuse(1, eth1addr);
Simon Glass64b723f2017-08-03 12:22:12 -0600134 if (!env_get("eth1addr") && is_valid_ethaddr(eth1addr))
Simon Glass8551d552017-08-03 12:22:11 -0600135 eth_env_set_enetaddr("eth1addr", eth1addr);
Christoph Fritzd1708642016-11-29 16:13:40 +0100136
137 imx_iomux_v3_setup_multiple_pads(fec1_pads, ARRAY_SIZE(fec1_pads));
138
139 /*
140 * Generate phy reference clock via pin IOMUX ENET_REF_CLK1/2 by erasing
141 * ENET1/2_TX_CLK_DIR gpr1[14:13], so that reference clock is driven by
142 * ref_enetpll0/1 and enable ENET1/2_TX_CLK output driver.
143 */
144 clrsetbits_le32(&iomuxc_regs->gpr[1],
145 IOMUX_GPR1_FEC1_CLOCK_MUX2_SEL_MASK |
146 IOMUX_GPR1_FEC2_CLOCK_MUX2_SEL_MASK,
147 IOMUX_GPR1_FEC1_CLOCK_MUX1_SEL_MASK |
148 IOMUX_GPR1_FEC2_CLOCK_MUX1_SEL_MASK);
149
150 ret = enable_fec_anatop_clock(0, ENET_50MHZ);
151 if (ret)
152 goto eth_fail;
153
154 /* reset phy */
155 gpio_direction_output(PHY_RESET, 0);
156 mdelay(16);
157 gpio_set_value(PHY_RESET, 1);
158 mdelay(1);
159
160 ret = fecmxc_initialize_multi(bis, 0, CONFIG_FEC_MXC_PHYADDR,
161 IMX_FEC_BASE);
162 if (ret)
163 goto eth_fail;
164
165 return ret;
166
167eth_fail:
168 printf("FEC MXC: %s:failed (%i)\n", __func__, ret);
169 gpio_set_value(PHY_RESET, 0);
170 return ret;
171}
172
173#define PC MUX_PAD_CTRL(I2C_PAD_CTRL)
174/* I2C1 for PMIC */
175static struct i2c_pads_info i2c_pad_info1 = {
176 .scl = {
177 .i2c_mode = MX6_PAD_GPIO1_IO00__I2C1_SCL | PC,
178 .gpio_mode = MX6_PAD_GPIO1_IO00__GPIO1_IO_0 | PC,
179 .gp = IMX_GPIO_NR(1, 0),
180 },
181 .sda = {
182 .i2c_mode = MX6_PAD_GPIO1_IO01__I2C1_SDA | PC,
183 .gpio_mode = MX6_PAD_GPIO1_IO01__GPIO1_IO_1 | PC,
184 .gp = IMX_GPIO_NR(1, 1),
185 },
186};
187
188static struct pmic *pfuze_init(unsigned char i2cbus)
189{
190 struct pmic *p;
191 int ret;
192 u32 reg;
193
194 ret = power_pfuze100_init(i2cbus);
195 if (ret)
196 return NULL;
197
198 p = pmic_get("PFUZE100");
199 ret = pmic_probe(p);
200 if (ret)
201 return NULL;
202
203 pmic_reg_read(p, PFUZE100_DEVICEID, &reg);
204 printf("PMIC: PFUZE100 ID=0x%02x\n", reg);
205
206 /* Set SW1AB stanby volage to 0.975V */
207 pmic_reg_read(p, PFUZE100_SW1ABSTBY, &reg);
208 reg &= ~SW1x_STBY_MASK;
209 reg |= SW1x_0_975V;
210 pmic_reg_write(p, PFUZE100_SW1ABSTBY, reg);
211
212 /* Set SW1AB/VDDARM step ramp up time from 16us to 4us/25mV */
213 pmic_reg_read(p, PFUZE100_SW1ABCONF, &reg);
214 reg &= ~SW1xCONF_DVSSPEED_MASK;
215 reg |= SW1xCONF_DVSSPEED_4US;
216 pmic_reg_write(p, PFUZE100_SW1ABCONF, reg);
217
218 /* Set SW1C standby voltage to 0.975V */
219 pmic_reg_read(p, PFUZE100_SW1CSTBY, &reg);
220 reg &= ~SW1x_STBY_MASK;
221 reg |= SW1x_0_975V;
222 pmic_reg_write(p, PFUZE100_SW1CSTBY, reg);
223
224 /* Set SW1C/VDDSOC step ramp up time from 16us to 4us/25mV */
225 pmic_reg_read(p, PFUZE100_SW1CCONF, &reg);
226 reg &= ~SW1xCONF_DVSSPEED_MASK;
227 reg |= SW1xCONF_DVSSPEED_4US;
228 pmic_reg_write(p, PFUZE100_SW1CCONF, reg);
229
230 return p;
231}
232
233static int pfuze_mode_init(struct pmic *p, u32 mode)
234{
235 unsigned char offset, i, switch_num;
236 u32 id;
237 int ret;
238
239 pmic_reg_read(p, PFUZE100_DEVICEID, &id);
240 id = id & 0xf;
241
242 if (id == 0) {
243 switch_num = 6;
244 offset = PFUZE100_SW1CMODE;
245 } else if (id == 1) {
246 switch_num = 4;
247 offset = PFUZE100_SW2MODE;
248 } else {
249 printf("Not supported, id=%d\n", id);
250 return -EINVAL;
251 }
252
253 ret = pmic_reg_write(p, PFUZE100_SW1ABMODE, mode);
254 if (ret < 0) {
255 printf("Set SW1AB mode error!\n");
256 return ret;
257 }
258
259 for (i = 0; i < switch_num - 1; i++) {
260 ret = pmic_reg_write(p, offset + i * SWITCH_SIZE, mode);
261 if (ret < 0) {
262 printf("Set switch 0x%x mode error!\n",
263 offset + i * SWITCH_SIZE);
264 return ret;
265 }
266 }
267
268 return ret;
269}
270
271int power_init_board(void)
272{
273 struct pmic *p;
274 int ret;
275
276 p = pfuze_init(I2C_PMIC);
277 if (!p)
278 return -ENODEV;
279
280 ret = pfuze_mode_init(p, APS_PFM);
281 if (ret < 0)
282 return ret;
283
284 return 0;
285}
286
287#ifdef CONFIG_USB_EHCI_MX6
288static iomux_v3_cfg_t const usb_otg_pads[] = {
289 /* OGT1 */
290 MX6_PAD_GPIO1_IO09__USB_OTG1_PWR | MUX_PAD_CTRL(NO_PAD_CTRL),
291 MX6_PAD_GPIO1_IO10__ANATOP_OTG1_ID | MUX_PAD_CTRL(NO_PAD_CTRL),
292 /* OTG2 */
293 MX6_PAD_GPIO1_IO12__USB_OTG2_PWR | MUX_PAD_CTRL(NO_PAD_CTRL)
294};
295
296static void setup_iomux_usb(void)
297{
298 imx_iomux_v3_setup_multiple_pads(usb_otg_pads,
299 ARRAY_SIZE(usb_otg_pads));
300}
301
302int board_usb_phy_mode(int port)
303{
304 if (port == 1)
305 return USB_INIT_HOST;
306 else
307 return usb_phy_mode(port);
308}
309#endif
310
311#ifdef CONFIG_PWM_IMX
312static int set_pwm_leds(void)
313{
314 int ret;
315
316 imx_iomux_v3_setup_multiple_pads(pwm_led_pads,
317 ARRAY_SIZE(pwm_led_pads));
318 /* enable backlight PWM 2, green LED */
319 ret = pwm_init(1, 0, 0);
320 if (ret)
321 goto error;
322 /* duty cycle 200ns, period: 8000ns */
323 ret = pwm_config(1, 200, 8000);
324 if (ret)
325 goto error;
326 ret = pwm_enable(1);
327 if (ret)
328 goto error;
329
330 /* enable backlight PWM 1, blue LED */
331 ret = pwm_init(0, 0, 0);
332 if (ret)
333 goto error;
334 /* duty cycle 200ns, period: 8000ns */
335 ret = pwm_config(0, 200, 8000);
336 if (ret)
337 goto error;
338 ret = pwm_enable(0);
339 if (ret)
340 goto error;
341
342 /* enable backlight PWM 6, red LED */
343 ret = pwm_init(5, 0, 0);
344 if (ret)
345 goto error;
346 /* duty cycle 200ns, period: 8000ns */
347 ret = pwm_config(5, 200, 8000);
348 if (ret)
349 goto error;
350 ret = pwm_enable(5);
351
352error:
353 return ret;
354}
355#else
356static int set_pwm_leds(void)
357{
358 return 0;
359}
360#endif
361
362#define ADCx_HC0 0x00
363#define ADCx_HS 0x08
364#define ADCx_HS_C0 BIT(0)
365#define ADCx_R0 0x0c
366#define ADCx_CFG 0x14
367#define ADCx_CFG_SWMODE 0x308
368#define ADCx_GC 0x18
369#define ADCx_GC_CAL BIT(7)
370
371static int read_adc(u32 *val)
372{
373 int ret;
374 void __iomem *b = map_physmem(ADC1_BASE_ADDR, 0x100, MAP_NOCACHE);
375
376 /* use software mode */
377 writel(ADCx_CFG_SWMODE, b + ADCx_CFG);
378
379 /* start auto calibration */
380 setbits_le32(b + ADCx_GC, ADCx_GC_CAL);
381 ret = wait_for_bit("ADC", b + ADCx_GC, ADCx_GC_CAL, ADCx_GC_CAL, 10, 0);
382 if (ret)
383 goto adc_exit;
384
385 /* start conversion */
386 writel(0, b + ADCx_HC0);
387
388 /* wait for conversion */
389 ret = wait_for_bit("ADC", b + ADCx_HS, ADCx_HS_C0, ADCx_HS_C0, 10, 0);
390 if (ret)
391 goto adc_exit;
392
393 /* read result */
394 *val = readl(b + ADCx_R0);
395
396adc_exit:
397 if (ret)
398 printf("ADC failure (ret=%i)\n", ret);
399 unmap_physmem(b, MAP_NOCACHE);
400 return ret;
401}
402
403#define VAL_UPPER 2498
404#define VAL_LOWER 1550
405
406static int set_pin_state(void)
407{
408 u32 val;
409 int ret;
410
411 ret = read_adc(&val);
412 if (ret)
413 return ret;
414
415 if (val >= VAL_UPPER)
Simon Glass6a38e412017-08-03 12:22:09 -0600416 env_set("pin_state", "connected");
Christoph Fritzd1708642016-11-29 16:13:40 +0100417 else if (val < VAL_UPPER && val > VAL_LOWER)
Simon Glass6a38e412017-08-03 12:22:09 -0600418 env_set("pin_state", "open");
Christoph Fritzd1708642016-11-29 16:13:40 +0100419 else
Simon Glass6a38e412017-08-03 12:22:09 -0600420 env_set("pin_state", "button");
Christoph Fritzd1708642016-11-29 16:13:40 +0100421
422 return ret;
423}
424
425int board_late_init(void)
426{
427 int ret;
428
429 ret = set_pwm_leds();
430 if (ret)
431 return ret;
432
433 ret = set_pin_state();
434
435 return ret;
436}
437
438int board_early_init_f(void)
439{
440 setup_iomux_uart();
441
442 setup_iomux_usb();
443
444 return 0;
445}
446
447static struct fsl_esdhc_cfg usdhc_cfg[2] = {
448 {USDHC4_BASE_ADDR, 0, 8},
449 {USDHC2_BASE_ADDR, 0, 4},
450};
451
452#define USDHC2_CD_GPIO IMX_GPIO_NR(3, 28)
453
454int board_mmc_getcd(struct mmc *mmc)
455{
456 struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv;
457
458 if (cfg->esdhc_base == USDHC4_BASE_ADDR)
459 return 1;
460 if (cfg->esdhc_base == USDHC2_BASE_ADDR)
461 return !gpio_get_value(USDHC2_CD_GPIO);
462
463 return -EINVAL;
464}
465
466int board_mmc_init(bd_t *bis)
467{
468 int ret;
469
470 /*
471 * According to the board_mmc_init() the following map is done:
472 * (U-Boot device node) (Physical Port)
473 * mmc0 USDHC4
474 * mmc1 USDHC2
475 */
476 imx_iomux_v3_setup_multiple_pads(
477 usdhc4_pads, ARRAY_SIZE(usdhc4_pads));
478 usdhc_cfg[0].sdhc_clk = mxc_get_clock(MXC_ESDHC4_CLK);
479
480 imx_iomux_v3_setup_multiple_pads(
481 usdhc2_pads, ARRAY_SIZE(usdhc2_pads));
482 gpio_direction_input(USDHC2_CD_GPIO);
483 usdhc_cfg[1].sdhc_clk = mxc_get_clock(MXC_ESDHC2_CLK);
484
485 ret = fsl_esdhc_initialize(bis, &usdhc_cfg[0]);
486 if (ret) {
487 printf("Warning: failed to initialize USDHC4\n");
488 return ret;
489 }
490
491 ret = fsl_esdhc_initialize(bis, &usdhc_cfg[1]);
492 if (ret) {
493 printf("Warning: failed to initialize USDHC2\n");
494 return ret;
495 }
496
497 return 0;
498}
499
500int board_init(void)
501{
502 /* Address of boot parameters */
503 gd->bd->bi_boot_params = PHYS_SDRAM + 0x100;
504
505#ifdef CONFIG_SYS_I2C_MXC
506 setup_i2c(0, CONFIG_SYS_I2C_SPEED, 0x7f, &i2c_pad_info1);
507#endif
508
509 return 0;
510}
511
512int checkboard(void)
513{
514 puts("Board: VIN|ING 2000\n");
515
516 return 0;
517}