blob: f08f09e17f28945b6ed82753267b5237f7c39d92 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Heiko Schocherf853c6c2014-07-18 06:07:22 +02002/*
3 * (C) Copyright 2014
4 * Heiko Schocher, DENX Software Engineering, hs@denx.de.
5 *
6 * Based on:
7 * Copyright (C) 2012 Freescale Semiconductor, Inc.
8 *
9 * Author: Fabio Estevam <fabio.estevam@freescale.com>
Heiko Schocherf853c6c2014-07-18 06:07:22 +020010 */
11
12#include <asm/arch/clock.h>
13#include <asm/arch/imx-regs.h>
14#include <asm/arch/iomux.h>
15#include <asm/arch/mx6-pins.h>
Masahiro Yamada56a931c2016-09-21 11:28:55 +090016#include <linux/errno.h>
Heiko Schocherf853c6c2014-07-18 06:07:22 +020017#include <asm/gpio.h>
Stefano Babic33731bc2017-06-29 10:16:06 +020018#include <asm/mach-imx/iomux-v3.h>
19#include <asm/mach-imx/boot_mode.h>
20#include <asm/mach-imx/mxc_i2c.h>
21#include <asm/mach-imx/video.h>
Heiko Schocherf853c6c2014-07-18 06:07:22 +020022#include <asm/arch/mxc_hdmi.h>
23#include <asm/arch/crm_regs.h>
24#include <linux/fb.h>
25#include <ipu_pixfmt.h>
Diego Dorta2661c9c2017-09-22 12:12:18 -030026#include <input.h>
Heiko Schocherf853c6c2014-07-18 06:07:22 +020027#include <asm/io.h>
28#include <asm/arch/sys_proto.h>
29#include <pwm.h>
Heiko Schocher54333792019-12-01 11:23:12 +010030#include <dm/root.h>
Heiko Schochera051ee92019-12-01 11:23:11 +010031#include <env.h>
32#include <micrel.h>
Heiko Schocher441b0542019-12-01 11:23:18 +010033#include <miiphy.h>
Heiko Schochera051ee92019-12-01 11:23:11 +010034#include <video.h>
35#include <../drivers/video/imx/ipu.h>
36#if defined(CONFIG_VIDEO_BMP_LOGO)
37 #include <bmp_logo.h>
38#endif
Heiko Schocher495956b2019-12-01 11:23:15 +010039#include <led.h>
Heiko Schocherf853c6c2014-07-18 06:07:22 +020040
41DECLARE_GLOBAL_DATA_PTR;
42
Heiko Schocherf853c6c2014-07-18 06:07:22 +020043#define I2C_PAD_CTRL (PAD_CTL_PUS_100K_UP | \
44 PAD_CTL_SPEED_MED | PAD_CTL_DSE_40ohm | PAD_CTL_HYS | \
45 PAD_CTL_ODE | PAD_CTL_SRE_FAST)
46
47#define PC MUX_PAD_CTRL(I2C_PAD_CTRL)
48
49#define DISP_PAD_CTRL (0x10)
50
Heiko Schocher54333792019-12-01 11:23:12 +010051enum {
52 BOARD_TYPE_4 = 4,
53 BOARD_TYPE_7 = 7,
54};
55
56#define ARI_BT_4 "aristainetos2_4@2"
57#define ARI_BT_7 "aristainetos2_7@1"
58
Heiko Schochera051ee92019-12-01 11:23:11 +010059struct i2c_pads_info i2c_pad_info3 = {
60 .scl = {
61 .i2c_mode = MX6_PAD_GPIO_5__I2C3_SCL | PC,
62 .gpio_mode = MX6_PAD_GPIO_5__GPIO1_IO05 | PC,
63 .gp = IMX_GPIO_NR(1, 5)
64 },
65 .sda = {
66 .i2c_mode = MX6_PAD_GPIO_6__I2C3_SDA | PC,
67 .gpio_mode = MX6_PAD_GPIO_6__GPIO1_IO06 | PC,
68 .gp = IMX_GPIO_NR(1, 6)
69 }
70};
71
72struct i2c_pads_info i2c_pad_info4 = {
73 .scl = {
74 .i2c_mode = MX6_PAD_GPIO_7__I2C4_SCL | PC,
75 .gpio_mode = MX6_PAD_GPIO_7__GPIO1_IO07 | PC,
76 .gp = IMX_GPIO_NR(1, 7)
77 },
78 .sda = {
79 .i2c_mode = MX6_PAD_GPIO_8__I2C4_SDA | PC,
80 .gpio_mode = MX6_PAD_GPIO_8__GPIO1_IO08 | PC,
81 .gp = IMX_GPIO_NR(1, 8)
82 }
83};
84
Heiko Schochera051ee92019-12-01 11:23:11 +010085static iomux_v3_cfg_t const backlight_pads[] = {
86 /* backlight PWM brightness control */
87 MX6_PAD_GPIO_9__PWM1_OUT | MUX_PAD_CTRL(NO_PAD_CTRL),
88 /* backlight enable */
89 MX6_PAD_EIM_BCLK__GPIO6_IO31 | MUX_PAD_CTRL(NO_PAD_CTRL),
90 /* LCD power enable */
91 MX6_PAD_NANDF_CS2__GPIO6_IO15 | MUX_PAD_CTRL(NO_PAD_CTRL),
92};
93
Heiko Schochera051ee92019-12-01 11:23:11 +010094static iomux_v3_cfg_t const display_pads[] = {
95 MX6_PAD_DI0_DISP_CLK__IPU1_DI0_DISP_CLK | MUX_PAD_CTRL(DISP_PAD_CTRL),
96 MX6_PAD_DI0_PIN15__IPU1_DI0_PIN15,
97 MX6_PAD_DI0_PIN2__IPU1_DI0_PIN02,
98 MX6_PAD_DI0_PIN3__IPU1_DI0_PIN03,
99 MX6_PAD_DISP0_DAT0__IPU1_DISP0_DATA00,
100 MX6_PAD_DISP0_DAT1__IPU1_DISP0_DATA01,
101 MX6_PAD_DISP0_DAT2__IPU1_DISP0_DATA02,
102 MX6_PAD_DISP0_DAT3__IPU1_DISP0_DATA03,
103 MX6_PAD_DISP0_DAT4__IPU1_DISP0_DATA04,
104 MX6_PAD_DISP0_DAT5__IPU1_DISP0_DATA05,
105 MX6_PAD_DISP0_DAT6__IPU1_DISP0_DATA06,
106 MX6_PAD_DISP0_DAT7__IPU1_DISP0_DATA07,
107 MX6_PAD_DISP0_DAT8__IPU1_DISP0_DATA08,
108 MX6_PAD_DISP0_DAT9__IPU1_DISP0_DATA09,
109 MX6_PAD_DISP0_DAT10__IPU1_DISP0_DATA10,
110 MX6_PAD_DISP0_DAT11__IPU1_DISP0_DATA11,
111 MX6_PAD_DISP0_DAT12__IPU1_DISP0_DATA12,
112 MX6_PAD_DISP0_DAT13__IPU1_DISP0_DATA13,
113 MX6_PAD_DISP0_DAT14__IPU1_DISP0_DATA14,
114 MX6_PAD_DISP0_DAT15__IPU1_DISP0_DATA15,
115 MX6_PAD_DISP0_DAT16__IPU1_DISP0_DATA16,
116 MX6_PAD_DISP0_DAT17__IPU1_DISP0_DATA17,
117 MX6_PAD_DISP0_DAT18__IPU1_DISP0_DATA18,
118 MX6_PAD_DISP0_DAT19__IPU1_DISP0_DATA19,
119 MX6_PAD_DISP0_DAT20__IPU1_DISP0_DATA20,
120 MX6_PAD_DISP0_DAT21__IPU1_DISP0_DATA21,
121 MX6_PAD_DISP0_DAT22__IPU1_DISP0_DATA22,
122 MX6_PAD_DISP0_DAT23__IPU1_DISP0_DATA23,
123};
124
Heiko Schochera051ee92019-12-01 11:23:11 +0100125int board_phy_config(struct phy_device *phydev)
126{
127 /* control data pad skew - devaddr = 0x02, register = 0x04 */
128 ksz9031_phy_extended_write(phydev, 0x02,
129 MII_KSZ9031_EXT_RGMII_CTRL_SIG_SKEW,
130 MII_KSZ9031_MOD_DATA_NO_POST_INC, 0x0000);
131 /* rx data pad skew - devaddr = 0x02, register = 0x05 */
132 ksz9031_phy_extended_write(phydev, 0x02,
133 MII_KSZ9031_EXT_RGMII_RX_DATA_SKEW,
134 MII_KSZ9031_MOD_DATA_NO_POST_INC, 0x0000);
135 /* tx data pad skew - devaddr = 0x02, register = 0x06 */
136 ksz9031_phy_extended_write(phydev, 0x02,
137 MII_KSZ9031_EXT_RGMII_TX_DATA_SKEW,
138 MII_KSZ9031_MOD_DATA_NO_POST_INC, 0x0000);
139 /* gtx and rx clock pad skew - devaddr = 0x02, register = 0x08 */
140 ksz9031_phy_extended_write(phydev, 0x02,
141 MII_KSZ9031_EXT_RGMII_CLOCK_SKEW,
142 MII_KSZ9031_MOD_DATA_NO_POST_INC, 0x03FF);
143
144 if (phydev->drv->config)
145 phydev->drv->config(phydev);
146
147 return 0;
148}
149
Heiko Schochera051ee92019-12-01 11:23:11 +0100150static int rotate_logo_one(unsigned char *out, unsigned char *in)
151{
152 int i, j;
153
154 for (i = 0; i < BMP_LOGO_WIDTH; i++)
155 for (j = 0; j < BMP_LOGO_HEIGHT; j++)
156 out[j * BMP_LOGO_WIDTH + BMP_LOGO_HEIGHT - 1 - i] =
157 in[i * BMP_LOGO_WIDTH + j];
158 return 0;
159}
160
161/*
162 * Rotate the BMP_LOGO (only)
163 * Will only work, if the logo is square, as
164 * BMP_LOGO_HEIGHT and BMP_LOGO_WIDTH are defines, not variables
165 */
166void rotate_logo(int rotations)
167{
168 unsigned char out_logo[BMP_LOGO_WIDTH * BMP_LOGO_HEIGHT];
169 unsigned char *in_logo;
170 int i, j;
171
172 if (BMP_LOGO_WIDTH != BMP_LOGO_HEIGHT)
173 return;
174
175 in_logo = bmp_logo_bitmap;
176
177 /* one 90 degree rotation */
178 if (rotations == 1 || rotations == 2 || rotations == 3)
179 rotate_logo_one(out_logo, in_logo);
180
181 /* second 90 degree rotation */
182 if (rotations == 2 || rotations == 3)
183 rotate_logo_one(in_logo, out_logo);
184
185 /* third 90 degree rotation */
186 if (rotations == 3)
187 rotate_logo_one(out_logo, in_logo);
188
189 /* copy result back to original array */
190 if (rotations == 1 || rotations == 3)
191 for (i = 0; i < BMP_LOGO_WIDTH; i++)
192 for (j = 0; j < BMP_LOGO_HEIGHT; j++)
193 in_logo[i * BMP_LOGO_WIDTH + j] =
194 out_logo[i * BMP_LOGO_WIDTH + j];
195}
196
197static void enable_display_power(void)
198{
199 imx_iomux_v3_setup_multiple_pads(backlight_pads,
200 ARRAY_SIZE(backlight_pads));
201
202 /* backlight enable */
Heiko Schocher495956b2019-12-01 11:23:15 +0100203 gpio_request(IMX_GPIO_NR(6, 31), "backlight");
Heiko Schochera051ee92019-12-01 11:23:11 +0100204 gpio_direction_output(IMX_GPIO_NR(6, 31), 1);
Heiko Schocher495956b2019-12-01 11:23:15 +0100205 gpio_free(IMX_GPIO_NR(6, 31));
Heiko Schochera051ee92019-12-01 11:23:11 +0100206 /* LCD power enable */
Heiko Schocher495956b2019-12-01 11:23:15 +0100207 gpio_request(IMX_GPIO_NR(6, 15), "LCD_power_enable");
Heiko Schochera051ee92019-12-01 11:23:11 +0100208 gpio_direction_output(IMX_GPIO_NR(6, 15), 1);
Heiko Schocher495956b2019-12-01 11:23:15 +0100209 gpio_free(IMX_GPIO_NR(6, 15));
Heiko Schochera051ee92019-12-01 11:23:11 +0100210
211 /* enable backlight PWM 1 */
212 if (pwm_init(0, 0, 0))
213 goto error;
214 /* duty cycle 500ns, period: 3000ns */
215 if (pwm_config(0, 50000, 300000))
216 goto error;
217 if (pwm_enable(0))
218 goto error;
219 return;
220
221error:
222 puts("error init pwm for backlight\n");
223}
224
225static void enable_lvds(struct display_info_t const *dev)
226{
227 struct iomuxc *iomux = (struct iomuxc *)IOMUXC_BASE_ADDR;
228 struct mxc_ccm_reg *ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
229 int reg;
230 s32 timeout = 100000;
231
232 /* set PLL5 clock */
233 reg = readl(&ccm->analog_pll_video);
234 reg |= BM_ANADIG_PLL_VIDEO_POWERDOWN;
235 writel(reg, &ccm->analog_pll_video);
236
237 /* set PLL5 to 232720000Hz */
238 reg &= ~BM_ANADIG_PLL_VIDEO_DIV_SELECT;
239 reg |= BF_ANADIG_PLL_VIDEO_DIV_SELECT(0x26);
240 reg &= ~BM_ANADIG_PLL_VIDEO_POST_DIV_SELECT;
241 reg |= BF_ANADIG_PLL_VIDEO_POST_DIV_SELECT(0);
242 writel(reg, &ccm->analog_pll_video);
243
244 writel(BF_ANADIG_PLL_VIDEO_NUM_A(0xC0238),
245 &ccm->analog_pll_video_num);
246 writel(BF_ANADIG_PLL_VIDEO_DENOM_B(0xF4240),
247 &ccm->analog_pll_video_denom);
248
249 reg &= ~BM_ANADIG_PLL_VIDEO_POWERDOWN;
250 writel(reg, &ccm->analog_pll_video);
251
252 while (timeout--)
253 if (readl(&ccm->analog_pll_video) & BM_ANADIG_PLL_VIDEO_LOCK)
254 break;
255 if (timeout < 0)
256 printf("Warning: video pll lock timeout!\n");
257
258 reg = readl(&ccm->analog_pll_video);
259 reg |= BM_ANADIG_PLL_VIDEO_ENABLE;
260 reg &= ~BM_ANADIG_PLL_VIDEO_BYPASS;
261 writel(reg, &ccm->analog_pll_video);
262
263 /* set LDB0, LDB1 clk select to 000/000 (PLL5 clock) */
264 reg = readl(&ccm->cs2cdr);
265 reg &= ~(MXC_CCM_CS2CDR_LDB_DI0_CLK_SEL_MASK
266 | MXC_CCM_CS2CDR_LDB_DI1_CLK_SEL_MASK);
267 reg |= (0 << MXC_CCM_CS2CDR_LDB_DI0_CLK_SEL_OFFSET)
268 | (0 << MXC_CCM_CS2CDR_LDB_DI1_CLK_SEL_OFFSET);
269 writel(reg, &ccm->cs2cdr);
270
271 reg = readl(&ccm->cscmr2);
272 reg |= MXC_CCM_CSCMR2_LDB_DI0_IPU_DIV;
273 writel(reg, &ccm->cscmr2);
274
275 reg = readl(&ccm->chsccdr);
276 reg |= (CHSCCDR_CLK_SEL_LDB_DI0
277 << MXC_CCM_CHSCCDR_IPU1_DI0_CLK_SEL_OFFSET);
278 writel(reg, &ccm->chsccdr);
279
280 reg = IOMUXC_GPR2_BGREF_RRMODE_EXTERNAL_RES
281 | IOMUXC_GPR2_DI1_VS_POLARITY_ACTIVE_HIGH
282 | IOMUXC_GPR2_DI0_VS_POLARITY_ACTIVE_HIGH
283 | IOMUXC_GPR2_BIT_MAPPING_CH0_SPWG
284 | IOMUXC_GPR2_DATA_WIDTH_CH0_24BIT
285 | IOMUXC_GPR2_LVDS_CH1_MODE_DISABLED
286 | IOMUXC_GPR2_LVDS_CH0_MODE_ENABLED_DI0;
287 writel(reg, &iomux->gpr[2]);
288
289 reg = readl(&iomux->gpr[3]);
290 reg = (reg & ~IOMUXC_GPR3_LVDS0_MUX_CTL_MASK)
291 | (IOMUXC_GPR3_MUX_SRC_IPU1_DI0
292 << IOMUXC_GPR3_LVDS0_MUX_CTL_OFFSET);
293 writel(reg, &iomux->gpr[3]);
294}
295
296static void enable_spi_display(struct display_info_t const *dev)
297{
298 struct iomuxc *iomux = (struct iomuxc *)IOMUXC_BASE_ADDR;
299 struct mxc_ccm_reg *ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
300 int reg;
301 s32 timeout = 100000;
302
303#if defined(CONFIG_VIDEO_BMP_LOGO)
304 rotate_logo(3); /* portrait display in landscape mode */
305#endif
306
307 /*
308 * set ldb clock to 28341000 Hz calculated through the formula:
309 * (XRES + LEFT_M + RIGHT_M + HSYNC_LEN) *
310 * (YRES + UPPER_M + LOWER_M + VSYNC_LEN) * REFRESH)
311 * see:
312 * https://community.freescale.com/thread/308170
313 */
314 ipu_set_ldb_clock(28341000);
315
316 reg = readl(&ccm->cs2cdr);
317
318 /* select pll 5 clock */
319 reg &= ~(MXC_CCM_CS2CDR_LDB_DI0_CLK_SEL_MASK
320 | MXC_CCM_CS2CDR_LDB_DI1_CLK_SEL_MASK);
321 writel(reg, &ccm->cs2cdr);
322
323 /* set PLL5 to 197994996Hz */
324 reg &= ~BM_ANADIG_PLL_VIDEO_DIV_SELECT;
325 reg |= BF_ANADIG_PLL_VIDEO_DIV_SELECT(0x21);
326 reg &= ~BM_ANADIG_PLL_VIDEO_POST_DIV_SELECT;
327 reg |= BF_ANADIG_PLL_VIDEO_POST_DIV_SELECT(0);
328 writel(reg, &ccm->analog_pll_video);
329
330 writel(BF_ANADIG_PLL_VIDEO_NUM_A(0xfbf4),
331 &ccm->analog_pll_video_num);
332 writel(BF_ANADIG_PLL_VIDEO_DENOM_B(0xf4240),
333 &ccm->analog_pll_video_denom);
334
335 reg &= ~BM_ANADIG_PLL_VIDEO_POWERDOWN;
336 writel(reg, &ccm->analog_pll_video);
337
338 while (timeout--)
339 if (readl(&ccm->analog_pll_video) & BM_ANADIG_PLL_VIDEO_LOCK)
340 break;
341 if (timeout < 0)
342 printf("Warning: video pll lock timeout!\n");
343
344 reg = readl(&ccm->analog_pll_video);
345 reg |= BM_ANADIG_PLL_VIDEO_ENABLE;
346 reg &= ~BM_ANADIG_PLL_VIDEO_BYPASS;
347 writel(reg, &ccm->analog_pll_video);
348
349 /* set LDB0, LDB1 clk select to 000/000 (PLL5 clock) */
350 reg = readl(&ccm->cs2cdr);
351 reg &= ~(MXC_CCM_CS2CDR_LDB_DI0_CLK_SEL_MASK
352 | MXC_CCM_CS2CDR_LDB_DI1_CLK_SEL_MASK);
353 reg |= (0 << MXC_CCM_CS2CDR_LDB_DI0_CLK_SEL_OFFSET)
354 | (0 << MXC_CCM_CS2CDR_LDB_DI1_CLK_SEL_OFFSET);
355 writel(reg, &ccm->cs2cdr);
356
357 reg = readl(&ccm->cscmr2);
358 reg |= MXC_CCM_CSCMR2_LDB_DI0_IPU_DIV;
359 writel(reg, &ccm->cscmr2);
360
361 reg = readl(&ccm->chsccdr);
362 reg |= (CHSCCDR_CLK_SEL_LDB_DI0
363 << MXC_CCM_CHSCCDR_IPU1_DI0_CLK_SEL_OFFSET);
364 reg &= ~MXC_CCM_CHSCCDR_IPU1_DI0_PODF_MASK;
365 reg |= (2 << MXC_CCM_CHSCCDR_IPU1_DI0_PODF_OFFSET);
366 reg &= ~MXC_CCM_CHSCCDR_IPU1_DI0_PRE_CLK_SEL_MASK;
367 reg |= (2 << MXC_CCM_CHSCCDR_IPU1_DI0_PRE_CLK_SEL_OFFSET);
368 writel(reg, &ccm->chsccdr);
369
370 reg = IOMUXC_GPR2_BGREF_RRMODE_EXTERNAL_RES
371 | IOMUXC_GPR2_DI1_VS_POLARITY_ACTIVE_HIGH
372 | IOMUXC_GPR2_DI0_VS_POLARITY_ACTIVE_HIGH
373 | IOMUXC_GPR2_BIT_MAPPING_CH0_SPWG
374 | IOMUXC_GPR2_DATA_WIDTH_CH0_24BIT
375 | IOMUXC_GPR2_LVDS_CH1_MODE_DISABLED
376 | IOMUXC_GPR2_LVDS_CH0_MODE_ENABLED_DI0;
377 writel(reg, &iomux->gpr[2]);
378
379 reg = readl(&iomux->gpr[3]);
380 reg = (reg & ~IOMUXC_GPR3_LVDS0_MUX_CTL_MASK)
381 | (IOMUXC_GPR3_MUX_SRC_IPU1_DI0
382 << IOMUXC_GPR3_LVDS0_MUX_CTL_OFFSET);
383 writel(reg, &iomux->gpr[3]);
384
385 imx_iomux_v3_setup_multiple_pads(display_pads,
386 ARRAY_SIZE(display_pads));
387}
388
389static void setup_display(void)
390{
391 enable_ipu_clock();
392 enable_display_power();
393}
394
Heiko Schochera051ee92019-12-01 11:23:11 +0100395static void set_gpr_register(void)
396{
397 struct iomuxc *iomuxc_regs = (struct iomuxc *)IOMUXC_BASE_ADDR;
398
399 writel(IOMUXC_GPR1_APP_CLK_REQ_N | IOMUXC_GPR1_PCIE_RDY_L23 |
400 IOMUXC_GPR1_EXC_MON_SLVE |
401 (2 << IOMUXC_GPR1_ADDRS0_OFFSET) |
402 IOMUXC_GPR1_ACT_CS0,
403 &iomuxc_regs->gpr[1]);
404 writel(0x0, &iomuxc_regs->gpr[8]);
405 writel(IOMUXC_GPR12_ARMP_IPG_CLK_EN | IOMUXC_GPR12_ARMP_AHB_CLK_EN |
406 IOMUXC_GPR12_ARMP_ATB_CLK_EN | IOMUXC_GPR12_ARMP_APB_CLK_EN,
407 &iomuxc_regs->gpr[12]);
408}
409
Heiko Schocher54333792019-12-01 11:23:12 +0100410extern char __bss_start[], __bss_end[];
Heiko Schochera051ee92019-12-01 11:23:11 +0100411int board_early_init_f(void)
412{
Heiko Schochera051ee92019-12-01 11:23:11 +0100413 setup_display();
414 set_gpr_register();
Heiko Schocher54333792019-12-01 11:23:12 +0100415
416 /*
417 * clear bss here, so we can use spi driver
418 * before relocation and read Environment
419 * from spi flash.
420 */
421 memset(__bss_start, 0x00, __bss_end - __bss_start);
422
Heiko Schochera051ee92019-12-01 11:23:11 +0100423 return 0;
424}
425
426static void setup_i2c4(void)
427{
428 setup_i2c(3, CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE,
429 &i2c_pad_info4);
430}
431
Heiko Schocher495956b2019-12-01 11:23:15 +0100432static void setup_one_led(char *label, int state)
Heiko Schochera051ee92019-12-01 11:23:11 +0100433{
Heiko Schocher495956b2019-12-01 11:23:15 +0100434 struct udevice *dev;
435 int ret;
Heiko Schochera051ee92019-12-01 11:23:11 +0100436
Heiko Schocher495956b2019-12-01 11:23:15 +0100437 ret = led_get_by_label(label, &dev);
438 if (ret == 0)
439 led_set_state(dev, state);
440}
441
442static void setup_board_gpio(void)
443{
444 setup_one_led("led_ena", LEDST_ON);
Heiko Schochera051ee92019-12-01 11:23:11 +0100445 /* switch off Status LEDs */
Heiko Schocher495956b2019-12-01 11:23:15 +0100446 setup_one_led("led_yellow", LEDST_OFF);
447 setup_one_led("led_red", LEDST_OFF);
448 setup_one_led("led_green", LEDST_OFF);
449 setup_one_led("led_blue", LEDST_OFF);
Heiko Schochera051ee92019-12-01 11:23:11 +0100450}
451
Heiko Schochera051ee92019-12-01 11:23:11 +0100452int board_late_init(void)
453{
454 char *my_bootdelay;
455 char bootmode = 0;
456 char const *panel = env_get("panel");
Heiko Schocher495956b2019-12-01 11:23:15 +0100457 struct gpio_desc *desc;
458 int ret;
Heiko Schochera051ee92019-12-01 11:23:11 +0100459
Heiko Schocher495956b2019-12-01 11:23:15 +0100460 led_default_state();
Heiko Schochera051ee92019-12-01 11:23:11 +0100461 /*
462 * Check the boot-source. If booting from NOR Flash,
463 * disable bootdelay
464 */
Heiko Schocher495956b2019-12-01 11:23:15 +0100465 desc = gpio_hog_lookup_name("bootsel0");
466 if (desc)
467 bootmode |= (dm_gpio_get_value(desc) ? 1 : 0) << 0;
468 desc = gpio_hog_lookup_name("bootsel1");
469 if (desc)
470 bootmode |= (dm_gpio_get_value(desc) ? 1 : 0) << 1;
471 desc = gpio_hog_lookup_name("bootsel2");
472 if (desc)
473 bootmode |= (dm_gpio_get_value(desc) ? 1 : 0) << 2;
Heiko Schochera051ee92019-12-01 11:23:11 +0100474
475 if (bootmode == 7) {
476 my_bootdelay = env_get("nor_bootdelay");
477 if (my_bootdelay != NULL)
478 env_set("bootdelay", my_bootdelay);
479 else
480 env_set("bootdelay", "-2");
481 }
482
Heiko Schocher495956b2019-12-01 11:23:15 +0100483 /* read out some jumper values*/
484 ret = gpio_hog_lookup_name("env_reset", &desc);
485 if (!ret) {
486 if (dm_gpio_get_value(desc)) {
487 printf("\nClear env (set back to defaults)\n");
488 run_command("run default_env; saveenv; saveenv", 0);
489 }
490 }
491 ret = gpio_hog_lookup_name("boot_rescue", &desc);
492 if (!ret) {
493 if (dm_gpio_get_value(desc)) {
494 aristainetos_run_rescue_command(16);
495 run_command("run rescue_xload_boot", 0);
496 }
497 }
498
Heiko Schochera051ee92019-12-01 11:23:11 +0100499 /* if we have the lg panel, we can initialze it now */
500 if (panel)
501 if (!strcmp(panel, displays[1].mode.name))
502 lg4573_spi_startup(CONFIG_LG4573_BUS,
503 CONFIG_LG4573_CS,
504 10000000, SPI_MODE_0);
Heiko Schocher05729822015-05-18 13:32:31 +0200505
Heiko Schocher54333792019-12-01 11:23:12 +0100506 /* set board_type */
507 if (gd->board_type == BOARD_TYPE_4)
508 env_set("board_type", ARI_BT_4);
509 else
510 env_set("board_type", ARI_BT_7);
511
Heiko Schochera051ee92019-12-01 11:23:11 +0100512 return 0;
513}
Heiko Schocher05729822015-05-18 13:32:31 +0200514
Heiko Schocherf853c6c2014-07-18 06:07:22 +0200515struct i2c_pads_info i2c_pad_info1 = {
516 .scl = {
517 .i2c_mode = MX6_PAD_CSI0_DAT9__I2C1_SCL | PC,
518 .gpio_mode = MX6_PAD_CSI0_DAT9__GPIO5_IO27 | PC,
519 .gp = IMX_GPIO_NR(5, 27)
520 },
521 .sda = {
522 .i2c_mode = MX6_PAD_CSI0_DAT8__I2C1_SDA | PC,
523 .gpio_mode = MX6_PAD_CSI0_DAT8__GPIO5_IO26 | PC,
524 .gp = IMX_GPIO_NR(5, 26)
525 }
526};
527
528struct i2c_pads_info i2c_pad_info2 = {
529 .scl = {
530 .i2c_mode = MX6_PAD_KEY_COL3__I2C2_SCL | PC,
531 .gpio_mode = MX6_PAD_KEY_COL3__GPIO4_IO12 | PC,
532 .gp = IMX_GPIO_NR(4, 12)
533 },
534 .sda = {
535 .i2c_mode = MX6_PAD_KEY_ROW3__I2C2_SDA | PC,
536 .gpio_mode = MX6_PAD_KEY_ROW3__GPIO4_IO13 | PC,
537 .gp = IMX_GPIO_NR(4, 13)
538 }
539};
540
Heiko Schocher05729822015-05-18 13:32:31 +0200541int dram_init(void)
Heiko Schocherf853c6c2014-07-18 06:07:22 +0200542{
Fabio Estevam1b23fe52016-07-23 13:23:39 -0300543 gd->ram_size = imx_ddr_size();
Heiko Schocherf853c6c2014-07-18 06:07:22 +0200544
Heiko Schocher05729822015-05-18 13:32:31 +0200545 return 0;
Heiko Schocherf853c6c2014-07-18 06:07:22 +0200546}
547
Heiko Schocherf853c6c2014-07-18 06:07:22 +0200548struct display_info_t const displays[] = {
549 {
550 .bus = -1,
551 .addr = 0,
552 .pixfmt = IPU_PIX_FMT_RGB24,
553 .detect = NULL,
554 .enable = enable_lvds,
555 .mode = {
556 .name = "lb07wv8",
557 .refresh = 60,
558 .xres = 800,
559 .yres = 480,
Heiko Schocher27813292015-08-11 08:09:44 +0200560 .pixclock = 30066,
Heiko Schocherf853c6c2014-07-18 06:07:22 +0200561 .left_margin = 88,
562 .right_margin = 88,
Heiko Schocher27813292015-08-11 08:09:44 +0200563 .upper_margin = 20,
564 .lower_margin = 20,
Heiko Schocher69f0e442015-01-20 10:06:18 +0100565 .hsync_len = 80,
Heiko Schocher27813292015-08-11 08:09:44 +0200566 .vsync_len = 5,
567 .sync = FB_SYNC_EXT,
Heiko Schocherf853c6c2014-07-18 06:07:22 +0200568 .vmode = FB_VMODE_NONINTERLACED
569 }
570 }
Heiko Schocher8fb9f3f2015-08-24 11:36:40 +0200571#if ((CONFIG_SYS_BOARD_VERSION == 2) || (CONFIG_SYS_BOARD_VERSION == 3))
Heiko Schocher05729822015-05-18 13:32:31 +0200572 , {
573 .bus = -1,
574 .addr = 0,
575 .pixfmt = IPU_PIX_FMT_RGB24,
576 .detect = NULL,
577 .enable = enable_spi_display,
578 .mode = {
579 .name = "lg4573",
Heiko Schocher27813292015-08-11 08:09:44 +0200580 .refresh = 57,
Heiko Schocher05729822015-05-18 13:32:31 +0200581 .xres = 480,
582 .yres = 800,
583 .pixclock = 37037,
584 .left_margin = 59,
585 .right_margin = 10,
586 .upper_margin = 15,
587 .lower_margin = 15,
588 .hsync_len = 10,
589 .vsync_len = 15,
590 .sync = FB_SYNC_EXT | FB_SYNC_HOR_HIGH_ACT |
591 FB_SYNC_VERT_HIGH_ACT,
592 .vmode = FB_VMODE_NONINTERLACED
593 }
594 }
595#endif
Heiko Schocherf853c6c2014-07-18 06:07:22 +0200596};
597size_t display_count = ARRAY_SIZE(displays);
598
Heiko Schocherf853c6c2014-07-18 06:07:22 +0200599/* no console on this board */
600int board_cfb_skip(void)
601{
602 return 1;
603}
Heiko Schocherf853c6c2014-07-18 06:07:22 +0200604
605iomux_v3_cfg_t nfc_pads[] = {
606 MX6_PAD_NANDF_CLE__NAND_CLE | MUX_PAD_CTRL(NO_PAD_CTRL),
607 MX6_PAD_NANDF_ALE__NAND_ALE | MUX_PAD_CTRL(NO_PAD_CTRL),
608 MX6_PAD_NANDF_WP_B__NAND_WP_B | MUX_PAD_CTRL(NO_PAD_CTRL),
609 MX6_PAD_NANDF_RB0__NAND_READY_B | MUX_PAD_CTRL(NO_PAD_CTRL),
610 MX6_PAD_NANDF_CS0__NAND_CE0_B | MUX_PAD_CTRL(NO_PAD_CTRL),
Heiko Schocherf853c6c2014-07-18 06:07:22 +0200611 MX6_PAD_SD4_CMD__NAND_RE_B | MUX_PAD_CTRL(NO_PAD_CTRL),
612 MX6_PAD_SD4_CLK__NAND_WE_B | MUX_PAD_CTRL(NO_PAD_CTRL),
613 MX6_PAD_NANDF_D0__NAND_DATA00 | MUX_PAD_CTRL(NO_PAD_CTRL),
614 MX6_PAD_NANDF_D1__NAND_DATA01 | MUX_PAD_CTRL(NO_PAD_CTRL),
615 MX6_PAD_NANDF_D2__NAND_DATA02 | MUX_PAD_CTRL(NO_PAD_CTRL),
616 MX6_PAD_NANDF_D3__NAND_DATA03 | MUX_PAD_CTRL(NO_PAD_CTRL),
617 MX6_PAD_NANDF_D4__NAND_DATA04 | MUX_PAD_CTRL(NO_PAD_CTRL),
618 MX6_PAD_NANDF_D5__NAND_DATA05 | MUX_PAD_CTRL(NO_PAD_CTRL),
619 MX6_PAD_NANDF_D6__NAND_DATA06 | MUX_PAD_CTRL(NO_PAD_CTRL),
620 MX6_PAD_NANDF_D7__NAND_DATA07 | MUX_PAD_CTRL(NO_PAD_CTRL),
621 MX6_PAD_SD4_DAT0__NAND_DQS | MUX_PAD_CTRL(NO_PAD_CTRL),
622};
623
624static void setup_gpmi_nand(void)
625{
626 struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
627
628 /* config gpmi nand iomux */
629 imx_iomux_v3_setup_multiple_pads(nfc_pads,
630 ARRAY_SIZE(nfc_pads));
631
Heiko Schocher05729822015-05-18 13:32:31 +0200632 /* gate ENFC_CLK_ROOT clock first,before clk source switch */
633 clrbits_le32(&mxc_ccm->CCGR2, MXC_CCM_CCGR2_IOMUX_IPT_CLK_IO_MASK);
634
Heiko Schocherf853c6c2014-07-18 06:07:22 +0200635 /* config gpmi and bch clock to 100 MHz */
636 clrsetbits_le32(&mxc_ccm->cs2cdr,
637 MXC_CCM_CS2CDR_ENFC_CLK_PODF_MASK |
638 MXC_CCM_CS2CDR_ENFC_CLK_PRED_MASK |
639 MXC_CCM_CS2CDR_ENFC_CLK_SEL_MASK,
640 MXC_CCM_CS2CDR_ENFC_CLK_PODF(0) |
641 MXC_CCM_CS2CDR_ENFC_CLK_PRED(3) |
642 MXC_CCM_CS2CDR_ENFC_CLK_SEL(3));
643
Heiko Schocher05729822015-05-18 13:32:31 +0200644 /* enable ENFC_CLK_ROOT clock */
645 setbits_le32(&mxc_ccm->CCGR2, MXC_CCM_CCGR2_IOMUX_IPT_CLK_IO_MASK);
646
Heiko Schocherf853c6c2014-07-18 06:07:22 +0200647 /* enable gpmi and bch clock gating */
648 setbits_le32(&mxc_ccm->CCGR4,
649 MXC_CCM_CCGR4_RAWNAND_U_BCH_INPUT_APB_MASK |
650 MXC_CCM_CCGR4_RAWNAND_U_GPMI_BCH_INPUT_BCH_MASK |
651 MXC_CCM_CCGR4_RAWNAND_U_GPMI_BCH_INPUT_GPMI_IO_MASK |
652 MXC_CCM_CCGR4_RAWNAND_U_GPMI_INPUT_APB_MASK |
653 MXC_CCM_CCGR4_PL301_MX6QPER1_BCH_OFFSET);
654
655 /* enable apbh clock gating */
656 setbits_le32(&mxc_ccm->CCGR0, MXC_CCM_CCGR0_APBHDMA_MASK);
657}
658
659int board_init(void)
660{
661 struct iomuxc *iomux = (struct iomuxc *)IOMUXC_BASE_ADDR;
662
663 /* address of boot parameters */
664 gd->bd->bi_boot_params = PHYS_SDRAM + 0x100;
665
Heiko Schocherf853c6c2014-07-18 06:07:22 +0200666 setup_i2c(0, CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE,
667 &i2c_pad_info1);
668 setup_i2c(1, CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE,
669 &i2c_pad_info2);
670 setup_i2c(2, CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE,
671 &i2c_pad_info3);
Heiko Schocher05729822015-05-18 13:32:31 +0200672 setup_i2c4();
Heiko Schocherf853c6c2014-07-18 06:07:22 +0200673
Heiko Schocher05729822015-05-18 13:32:31 +0200674 setup_board_gpio();
Heiko Schocherf853c6c2014-07-18 06:07:22 +0200675 setup_gpmi_nand();
676
677 /* GPIO_1 for USB_OTG_ID */
Heiko Schocher05729822015-05-18 13:32:31 +0200678 clrsetbits_le32(&iomux->gpr[1], IOMUXC_GPR1_USB_OTG_ID_SEL_MASK, 0);
Heiko Schocherf853c6c2014-07-18 06:07:22 +0200679 return 0;
680}
681
682int checkboard(void)
683{
Heiko Schocher05729822015-05-18 13:32:31 +0200684 printf("Board: %s\n", CONFIG_BOARDNAME);
Heiko Schocherf853c6c2014-07-18 06:07:22 +0200685 return 0;
686}
687
Heiko Schocher54333792019-12-01 11:23:12 +0100688int board_fit_config_name_match(const char *name)
689{
690 if (gd->board_type == BOARD_TYPE_4 &&
691 strchr(name, 0x34))
692 return 0;
693
694 if (gd->board_type == BOARD_TYPE_7 &&
695 strchr(name, 0x37))
696 return 0;
697
698 return -1;
699}
700
701static void do_board_detect(void)
702{
703 int ret;
704 char s[30];
705
706 /* default use board type 7 */
707 gd->board_type = BOARD_TYPE_7;
708 if (env_init())
709 return;
710
711 ret = env_get_f("panel", s, sizeof(s));
712 if (ret < 0)
713 return;
714
715 if (!strncmp("lg4573", s, 6))
716 gd->board_type = BOARD_TYPE_4;
717}
718
719#ifdef CONFIG_DTB_RESELECT
720int embedded_dtb_select(void)
721{
722 int rescan;
723
724 do_board_detect();
725 fdtdec_resetup(&rescan);
726
Heiko Schocherf853c6c2014-07-18 06:07:22 +0200727 return 0;
728}
729#endif