2018-05-06 21:58:06 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0+
|
2013-03-11 08:44:53 +00:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2010-2013 Freescale Semiconductor, Inc.
|
|
|
|
* Copyright (C) 2013, Boundary Devices <info@boundarydevices.com>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <common.h>
|
2020-05-10 17:40:03 +00:00
|
|
|
#include <command.h>
|
2019-08-01 15:46:46 +00:00
|
|
|
#include <env.h>
|
2020-05-10 17:40:02 +00:00
|
|
|
#include <init.h>
|
2020-05-10 17:39:56 +00:00
|
|
|
#include <net.h>
|
2013-03-11 08:44:53 +00:00
|
|
|
#include <asm/io.h>
|
|
|
|
#include <asm/arch/clock.h>
|
|
|
|
#include <asm/arch/imx-regs.h>
|
|
|
|
#include <asm/arch/iomux.h>
|
|
|
|
#include <asm/arch/sys_proto.h>
|
|
|
|
#include <malloc.h>
|
|
|
|
#include <asm/arch/mx6-pins.h>
|
2020-05-10 17:40:11 +00:00
|
|
|
#include <linux/delay.h>
|
2016-09-21 02:28:55 +00:00
|
|
|
#include <linux/errno.h>
|
2013-03-11 08:44:53 +00:00
|
|
|
#include <asm/gpio.h>
|
2017-06-29 08:16:06 +00:00
|
|
|
#include <asm/mach-imx/iomux-v3.h>
|
|
|
|
#include <asm/mach-imx/mxc_i2c.h>
|
|
|
|
#include <asm/mach-imx/sata.h>
|
|
|
|
#include <asm/mach-imx/spi.h>
|
|
|
|
#include <asm/mach-imx/boot_mode.h>
|
|
|
|
#include <asm/mach-imx/video.h>
|
2019-06-21 03:42:28 +00:00
|
|
|
#include <fsl_esdhc_imx.h>
|
2013-03-11 08:44:53 +00:00
|
|
|
#include <micrel.h>
|
|
|
|
#include <miiphy.h>
|
|
|
|
#include <netdev.h>
|
|
|
|
#include <asm/arch/crm_regs.h>
|
|
|
|
#include <asm/arch/mxc_hdmi.h>
|
|
|
|
#include <i2c.h>
|
2014-10-02 19:16:27 +00:00
|
|
|
#include <input.h>
|
|
|
|
#include <netdev.h>
|
2016-03-31 21:12:23 +00:00
|
|
|
#include <usb/ehci-ci.h>
|
2013-03-11 08:44:53 +00:00
|
|
|
|
|
|
|
DECLARE_GLOBAL_DATA_PTR;
|
2013-09-26 01:41:17 +00:00
|
|
|
#define GP_USB_OTG_PWR IMX_GPIO_NR(3, 22)
|
2013-03-11 08:44:53 +00:00
|
|
|
|
2013-04-26 01:34:47 +00:00
|
|
|
#define UART_PAD_CTRL (PAD_CTL_PUS_100K_UP | \
|
|
|
|
PAD_CTL_SPEED_MED | PAD_CTL_DSE_40ohm | \
|
|
|
|
PAD_CTL_SRE_FAST | PAD_CTL_HYS)
|
2013-03-11 08:44:53 +00:00
|
|
|
|
2013-04-26 01:34:47 +00:00
|
|
|
#define USDHC_PAD_CTRL (PAD_CTL_PUS_47K_UP | \
|
|
|
|
PAD_CTL_SPEED_LOW | PAD_CTL_DSE_80ohm | \
|
|
|
|
PAD_CTL_SRE_FAST | PAD_CTL_HYS)
|
2013-03-11 08:44:53 +00:00
|
|
|
|
2013-04-26 01:34:47 +00:00
|
|
|
#define ENET_PAD_CTRL (PAD_CTL_PUS_100K_UP | \
|
|
|
|
PAD_CTL_SPEED_MED | PAD_CTL_DSE_40ohm | PAD_CTL_HYS)
|
2013-03-11 08:44:53 +00:00
|
|
|
|
2013-04-26 01:34:47 +00:00
|
|
|
#define SPI_PAD_CTRL (PAD_CTL_HYS | PAD_CTL_SPEED_MED | \
|
2013-03-11 08:44:53 +00:00
|
|
|
PAD_CTL_DSE_40ohm | PAD_CTL_SRE_FAST)
|
|
|
|
|
2013-04-26 01:34:47 +00:00
|
|
|
#define BUTTON_PAD_CTRL (PAD_CTL_PUS_100K_UP | \
|
|
|
|
PAD_CTL_SPEED_MED | PAD_CTL_DSE_40ohm | PAD_CTL_HYS)
|
2013-03-11 08:44:53 +00:00
|
|
|
|
2013-04-26 01:34:47 +00:00
|
|
|
#define I2C_PAD_CTRL (PAD_CTL_PUS_100K_UP | \
|
|
|
|
PAD_CTL_SPEED_MED | PAD_CTL_DSE_40ohm | PAD_CTL_HYS | \
|
2013-03-11 08:44:53 +00:00
|
|
|
PAD_CTL_ODE | PAD_CTL_SRE_FAST)
|
|
|
|
|
2019-11-04 02:20:04 +00:00
|
|
|
#define RGB_PAD_CTRL PAD_CTL_DSE_120ohm
|
|
|
|
|
2013-04-26 01:34:47 +00:00
|
|
|
#define WEAK_PULLUP (PAD_CTL_PUS_100K_UP | \
|
|
|
|
PAD_CTL_SPEED_MED | PAD_CTL_DSE_40ohm | PAD_CTL_HYS | \
|
2013-03-11 08:44:53 +00:00
|
|
|
PAD_CTL_SRE_SLOW)
|
|
|
|
|
2013-04-26 01:34:47 +00:00
|
|
|
#define WEAK_PULLDOWN (PAD_CTL_PUS_100K_DOWN | \
|
|
|
|
PAD_CTL_SPEED_MED | PAD_CTL_DSE_40ohm | \
|
|
|
|
PAD_CTL_HYS | PAD_CTL_SRE_SLOW)
|
2013-03-11 08:44:53 +00:00
|
|
|
|
|
|
|
#define OUTPUT_40OHM (PAD_CTL_SPEED_MED|PAD_CTL_DSE_40ohm)
|
|
|
|
|
2019-11-04 02:20:04 +00:00
|
|
|
/* Prevent compiler error if gpio number 08 or 09 is used */
|
|
|
|
#define not_octal(gp) ((((0x##gp >> 4) & 0xf) * 10) + ((0x##gp & 0xf)))
|
|
|
|
|
|
|
|
#define _I2C_PADS_INFO_CPU(cpu, i2cnum, scl_pad, scl_bank, scl_gp, \
|
|
|
|
sda_pad, sda_bank, sda_gp, pad_ctrl, join_io) { \
|
|
|
|
.scl = { \
|
|
|
|
.i2c_mode = NEW_PAD_CTRL(cpu##_PAD_##scl_pad##__##i2cnum##_SCL,\
|
|
|
|
pad_ctrl), \
|
|
|
|
.gpio_mode = NEW_PAD_CTRL( \
|
|
|
|
cpu##_PAD_##scl_pad##__GPIO##scl_bank##join_io##scl_gp,\
|
|
|
|
pad_ctrl), \
|
|
|
|
.gp = IMX_GPIO_NR(scl_bank, not_octal(scl_gp)) \
|
|
|
|
}, \
|
|
|
|
.sda = { \
|
|
|
|
.i2c_mode = NEW_PAD_CTRL(cpu##_PAD_##sda_pad##__##i2cnum##_SDA,\
|
|
|
|
pad_ctrl), \
|
|
|
|
.gpio_mode = NEW_PAD_CTRL( \
|
|
|
|
cpu##_PAD_##sda_pad##__GPIO##sda_bank##join_io##sda_gp,\
|
|
|
|
pad_ctrl), \
|
|
|
|
.gp = IMX_GPIO_NR(sda_bank, not_octal(sda_gp)) \
|
|
|
|
} \
|
|
|
|
}
|
|
|
|
|
|
|
|
#define I2C_PADS_INFO_CPU(cpu, i2cnum, scl_pad, scl_bank, scl_gp, \
|
|
|
|
sda_pad, sda_bank, sda_gp, pad_ctrl) \
|
|
|
|
_I2C_PADS_INFO_CPU(cpu, i2cnum, scl_pad, scl_bank, scl_gp, \
|
|
|
|
sda_pad, sda_bank, sda_gp, pad_ctrl, _IO)
|
|
|
|
|
|
|
|
#if defined(CONFIG_MX6QDL)
|
|
|
|
#define I2C_PADS_INFO_ENTRY(i2cnum, scl_pad, scl_bank, scl_gp, \
|
|
|
|
sda_pad, sda_bank, sda_gp, pad_ctrl) \
|
|
|
|
I2C_PADS_INFO_CPU(MX6Q, i2cnum, scl_pad, scl_bank, scl_gp, \
|
|
|
|
sda_pad, sda_bank, sda_gp, pad_ctrl), \
|
|
|
|
I2C_PADS_INFO_CPU(MX6DL, i2cnum, scl_pad, scl_bank, scl_gp, \
|
|
|
|
sda_pad, sda_bank, sda_gp, pad_ctrl)
|
|
|
|
#define I2C_PADS_INFO_ENTRY_SPACING 2
|
|
|
|
|
|
|
|
#define IOMUX_PAD_CTRL(name, pad_ctrl) \
|
|
|
|
NEW_PAD_CTRL(MX6Q_PAD_##name, pad_ctrl), \
|
|
|
|
NEW_PAD_CTRL(MX6DL_PAD_##name, pad_ctrl)
|
|
|
|
#else
|
|
|
|
#define I2C_PADS_INFO_ENTRY(i2cnum, scl_pad, scl_bank, scl_gp, \
|
|
|
|
sda_pad, sda_bank, sda_gp, pad_ctrl) \
|
|
|
|
I2C_PADS_INFO_CPU(MX6, i2cnum, scl_pad, scl_bank, scl_gp, \
|
|
|
|
sda_pad, sda_bank, sda_gp, pad_ctrl)
|
|
|
|
#define I2C_PADS_INFO_ENTRY_SPACING 1
|
|
|
|
|
|
|
|
#define IOMUX_PAD_CTRL(name, pad_ctrl) NEW_PAD_CTRL(MX6_PAD_##name, pad_ctrl)
|
|
|
|
#endif
|
|
|
|
|
2013-03-11 08:44:53 +00:00
|
|
|
int dram_init(void)
|
|
|
|
{
|
2013-03-14 02:32:55 +00:00
|
|
|
gd->ram_size = ((ulong)CONFIG_DDR_MB * 1024 * 1024);
|
2013-03-11 08:44:53 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-10-02 19:16:27 +00:00
|
|
|
static iomux_v3_cfg_t const uart1_pads[] = {
|
2019-11-04 02:20:04 +00:00
|
|
|
IOMUX_PAD_CTRL(SD3_DAT6__UART1_RX_DATA, UART_PAD_CTRL),
|
|
|
|
IOMUX_PAD_CTRL(SD3_DAT7__UART1_TX_DATA, UART_PAD_CTRL),
|
2013-03-11 08:44:53 +00:00
|
|
|
};
|
|
|
|
|
2014-10-02 19:16:27 +00:00
|
|
|
static iomux_v3_cfg_t const uart2_pads[] = {
|
2019-11-04 02:20:04 +00:00
|
|
|
IOMUX_PAD_CTRL(EIM_D26__UART2_TX_DATA, UART_PAD_CTRL),
|
|
|
|
IOMUX_PAD_CTRL(EIM_D27__UART2_RX_DATA, UART_PAD_CTRL),
|
2013-03-11 08:44:53 +00:00
|
|
|
};
|
|
|
|
|
2019-11-04 02:20:04 +00:00
|
|
|
static struct i2c_pads_info i2c_pads[] = {
|
|
|
|
/* I2C1, SGTL5000 */
|
|
|
|
I2C_PADS_INFO_ENTRY(I2C1, EIM_D21, 3, 21, EIM_D28, 3, 28, I2C_PAD_CTRL),
|
|
|
|
/* I2C2 Camera, MIPI */
|
|
|
|
I2C_PADS_INFO_ENTRY(I2C2, KEY_COL3, 4, 12, KEY_ROW3, 4, 13,
|
|
|
|
I2C_PAD_CTRL),
|
|
|
|
/* I2C3, J15 - RGB connector */
|
|
|
|
I2C_PADS_INFO_ENTRY(I2C3, GPIO_5, 1, 05, GPIO_16, 7, 11, I2C_PAD_CTRL),
|
2013-03-11 08:44:53 +00:00
|
|
|
};
|
|
|
|
|
2019-11-04 02:20:04 +00:00
|
|
|
#define I2C_BUS_CNT 3
|
2013-03-11 08:44:53 +00:00
|
|
|
|
2014-10-02 19:16:24 +00:00
|
|
|
static iomux_v3_cfg_t const usdhc2_pads[] = {
|
2019-11-04 02:20:04 +00:00
|
|
|
IOMUX_PAD_CTRL(SD2_CLK__SD2_CLK, USDHC_PAD_CTRL),
|
|
|
|
IOMUX_PAD_CTRL(SD2_CMD__SD2_CMD, USDHC_PAD_CTRL),
|
|
|
|
IOMUX_PAD_CTRL(SD2_DAT0__SD2_DATA0, USDHC_PAD_CTRL),
|
|
|
|
IOMUX_PAD_CTRL(SD2_DAT1__SD2_DATA1, USDHC_PAD_CTRL),
|
|
|
|
IOMUX_PAD_CTRL(SD2_DAT2__SD2_DATA2, USDHC_PAD_CTRL),
|
|
|
|
IOMUX_PAD_CTRL(SD2_DAT3__SD2_DATA3, USDHC_PAD_CTRL),
|
2014-10-02 19:16:24 +00:00
|
|
|
};
|
|
|
|
|
2014-10-02 19:16:27 +00:00
|
|
|
static iomux_v3_cfg_t const enet_pads1[] = {
|
2019-11-04 02:20:04 +00:00
|
|
|
IOMUX_PAD_CTRL(ENET_MDIO__ENET_MDIO, ENET_PAD_CTRL),
|
|
|
|
IOMUX_PAD_CTRL(ENET_MDC__ENET_MDC, ENET_PAD_CTRL),
|
|
|
|
IOMUX_PAD_CTRL(RGMII_TXC__RGMII_TXC, ENET_PAD_CTRL),
|
|
|
|
IOMUX_PAD_CTRL(RGMII_TD0__RGMII_TD0, ENET_PAD_CTRL),
|
|
|
|
IOMUX_PAD_CTRL(RGMII_TD1__RGMII_TD1, ENET_PAD_CTRL),
|
|
|
|
IOMUX_PAD_CTRL(RGMII_TD2__RGMII_TD2, ENET_PAD_CTRL),
|
|
|
|
IOMUX_PAD_CTRL(RGMII_TD3__RGMII_TD3, ENET_PAD_CTRL),
|
|
|
|
IOMUX_PAD_CTRL(RGMII_TX_CTL__RGMII_TX_CTL, ENET_PAD_CTRL),
|
|
|
|
IOMUX_PAD_CTRL(ENET_REF_CLK__ENET_TX_CLK, ENET_PAD_CTRL),
|
2013-03-11 08:44:53 +00:00
|
|
|
/* pin 35 - 1 (PHY_AD2) on reset */
|
2019-11-04 02:20:04 +00:00
|
|
|
IOMUX_PAD_CTRL(RGMII_RXC__GPIO6_IO30, NO_PAD_CTRL),
|
2013-03-11 08:44:53 +00:00
|
|
|
/* pin 32 - 1 - (MODE0) all */
|
2019-11-04 02:20:04 +00:00
|
|
|
IOMUX_PAD_CTRL(RGMII_RD0__GPIO6_IO25, NO_PAD_CTRL),
|
2013-03-11 08:44:53 +00:00
|
|
|
/* pin 31 - 1 - (MODE1) all */
|
2019-11-04 02:20:04 +00:00
|
|
|
IOMUX_PAD_CTRL(RGMII_RD1__GPIO6_IO27, NO_PAD_CTRL),
|
2013-03-11 08:44:53 +00:00
|
|
|
/* pin 28 - 1 - (MODE2) all */
|
2019-11-04 02:20:04 +00:00
|
|
|
IOMUX_PAD_CTRL(RGMII_RD2__GPIO6_IO28, NO_PAD_CTRL),
|
2013-03-11 08:44:53 +00:00
|
|
|
/* pin 27 - 1 - (MODE3) all */
|
2019-11-04 02:20:04 +00:00
|
|
|
IOMUX_PAD_CTRL(RGMII_RD3__GPIO6_IO29, NO_PAD_CTRL),
|
2013-03-11 08:44:53 +00:00
|
|
|
/* pin 33 - 1 - (CLK125_EN) 125Mhz clockout enabled */
|
2019-11-04 02:20:04 +00:00
|
|
|
IOMUX_PAD_CTRL(RGMII_RX_CTL__GPIO6_IO24, NO_PAD_CTRL),
|
2013-03-11 08:44:53 +00:00
|
|
|
/* pin 42 PHY nRST */
|
2019-11-04 02:20:04 +00:00
|
|
|
IOMUX_PAD_CTRL(EIM_D23__GPIO3_IO23, NO_PAD_CTRL),
|
|
|
|
IOMUX_PAD_CTRL(ENET_RXD0__GPIO1_IO27, NO_PAD_CTRL),
|
2013-03-11 08:44:53 +00:00
|
|
|
};
|
|
|
|
|
2014-10-02 19:16:27 +00:00
|
|
|
static iomux_v3_cfg_t const enet_pads2[] = {
|
2019-11-04 02:20:04 +00:00
|
|
|
IOMUX_PAD_CTRL(RGMII_RXC__RGMII_RXC, ENET_PAD_CTRL),
|
|
|
|
IOMUX_PAD_CTRL(RGMII_RD0__RGMII_RD0, ENET_PAD_CTRL),
|
|
|
|
IOMUX_PAD_CTRL(RGMII_RD1__RGMII_RD1, ENET_PAD_CTRL),
|
|
|
|
IOMUX_PAD_CTRL(RGMII_RD2__RGMII_RD2, ENET_PAD_CTRL),
|
|
|
|
IOMUX_PAD_CTRL(RGMII_RD3__RGMII_RD3, ENET_PAD_CTRL),
|
|
|
|
IOMUX_PAD_CTRL(RGMII_RX_CTL__RGMII_RX_CTL, ENET_PAD_CTRL),
|
2013-03-11 08:44:53 +00:00
|
|
|
};
|
|
|
|
|
2013-09-26 01:41:17 +00:00
|
|
|
static iomux_v3_cfg_t const misc_pads[] = {
|
2019-11-04 02:20:04 +00:00
|
|
|
IOMUX_PAD_CTRL(GPIO_1__USB_OTG_ID, WEAK_PULLUP),
|
|
|
|
IOMUX_PAD_CTRL(KEY_COL4__USB_OTG_OC, WEAK_PULLUP),
|
|
|
|
IOMUX_PAD_CTRL(EIM_D30__USB_H1_OC, WEAK_PULLUP),
|
2013-09-26 01:41:17 +00:00
|
|
|
/* OTG Power enable */
|
2019-11-04 02:20:04 +00:00
|
|
|
IOMUX_PAD_CTRL(EIM_D22__GPIO3_IO22, OUTPUT_40OHM),
|
2013-09-26 01:41:17 +00:00
|
|
|
};
|
|
|
|
|
2013-03-11 08:44:53 +00:00
|
|
|
/* wl1271 pads on nitrogen6x */
|
2014-10-02 19:16:27 +00:00
|
|
|
static iomux_v3_cfg_t const wl12xx_pads[] = {
|
2019-11-04 02:20:04 +00:00
|
|
|
IOMUX_PAD_CTRL(NANDF_CS1__GPIO6_IO14, WEAK_PULLDOWN),
|
|
|
|
IOMUX_PAD_CTRL(NANDF_CS2__GPIO6_IO15, OUTPUT_40OHM),
|
|
|
|
IOMUX_PAD_CTRL(NANDF_CS3__GPIO6_IO16, OUTPUT_40OHM),
|
2013-03-11 08:44:53 +00:00
|
|
|
};
|
|
|
|
#define WL12XX_WL_IRQ_GP IMX_GPIO_NR(6, 14)
|
|
|
|
#define WL12XX_WL_ENABLE_GP IMX_GPIO_NR(6, 15)
|
|
|
|
#define WL12XX_BT_ENABLE_GP IMX_GPIO_NR(6, 16)
|
|
|
|
|
|
|
|
/* Button assignments for J14 */
|
|
|
|
static iomux_v3_cfg_t const button_pads[] = {
|
|
|
|
/* Menu */
|
2019-11-04 02:20:04 +00:00
|
|
|
IOMUX_PAD_CTRL(NANDF_D1__GPIO2_IO01, BUTTON_PAD_CTRL),
|
2013-03-11 08:44:53 +00:00
|
|
|
/* Back */
|
2019-11-04 02:20:04 +00:00
|
|
|
IOMUX_PAD_CTRL(NANDF_D2__GPIO2_IO02, BUTTON_PAD_CTRL),
|
2013-03-11 08:44:53 +00:00
|
|
|
/* Labelled Search (mapped to Power under Android) */
|
2019-11-04 02:20:04 +00:00
|
|
|
IOMUX_PAD_CTRL(NANDF_D3__GPIO2_IO03, BUTTON_PAD_CTRL),
|
2013-03-11 08:44:53 +00:00
|
|
|
/* Home */
|
2019-11-04 02:20:04 +00:00
|
|
|
IOMUX_PAD_CTRL(NANDF_D4__GPIO2_IO04, BUTTON_PAD_CTRL),
|
2013-03-11 08:44:53 +00:00
|
|
|
/* Volume Down */
|
2019-11-04 02:20:04 +00:00
|
|
|
IOMUX_PAD_CTRL(GPIO_19__GPIO4_IO05, BUTTON_PAD_CTRL),
|
2013-03-11 08:44:53 +00:00
|
|
|
/* Volume Up */
|
2019-11-04 02:20:04 +00:00
|
|
|
IOMUX_PAD_CTRL(GPIO_18__GPIO7_IO13, BUTTON_PAD_CTRL),
|
2013-03-11 08:44:53 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static void setup_iomux_enet(void)
|
|
|
|
{
|
|
|
|
gpio_direction_output(IMX_GPIO_NR(3, 23), 0); /* SABRE Lite PHY rst */
|
|
|
|
gpio_direction_output(IMX_GPIO_NR(1, 27), 0); /* Nitrogen6X PHY rst */
|
|
|
|
gpio_direction_output(IMX_GPIO_NR(6, 30), 1);
|
|
|
|
gpio_direction_output(IMX_GPIO_NR(6, 25), 1);
|
|
|
|
gpio_direction_output(IMX_GPIO_NR(6, 27), 1);
|
|
|
|
gpio_direction_output(IMX_GPIO_NR(6, 28), 1);
|
|
|
|
gpio_direction_output(IMX_GPIO_NR(6, 29), 1);
|
2019-11-04 02:20:04 +00:00
|
|
|
SETUP_IOMUX_PADS(enet_pads1);
|
2013-03-11 08:44:53 +00:00
|
|
|
gpio_direction_output(IMX_GPIO_NR(6, 24), 1);
|
|
|
|
|
|
|
|
/* Need delay 10ms according to KSZ9021 spec */
|
|
|
|
udelay(1000 * 10);
|
|
|
|
gpio_set_value(IMX_GPIO_NR(3, 23), 1); /* SABRE Lite PHY reset */
|
|
|
|
gpio_set_value(IMX_GPIO_NR(1, 27), 1); /* Nitrogen6X PHY reset */
|
|
|
|
|
2019-11-04 02:20:04 +00:00
|
|
|
SETUP_IOMUX_PADS(enet_pads2);
|
2014-10-02 19:16:29 +00:00
|
|
|
udelay(100); /* Wait 100 us before using mii interface */
|
2013-03-11 08:44:53 +00:00
|
|
|
}
|
|
|
|
|
2014-10-02 19:16:27 +00:00
|
|
|
static iomux_v3_cfg_t const usb_pads[] = {
|
2019-11-04 02:20:04 +00:00
|
|
|
IOMUX_PAD_CTRL(GPIO_17__GPIO7_IO12, NO_PAD_CTRL),
|
2013-03-11 08:44:53 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static void setup_iomux_uart(void)
|
|
|
|
{
|
2019-11-04 02:20:04 +00:00
|
|
|
SETUP_IOMUX_PADS(uart1_pads);
|
|
|
|
SETUP_IOMUX_PADS(uart2_pads);
|
2013-03-11 08:44:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef CONFIG_USB_EHCI_MX6
|
|
|
|
int board_ehci_hcd_init(int port)
|
|
|
|
{
|
2019-11-04 02:20:04 +00:00
|
|
|
SETUP_IOMUX_PADS(usb_pads);
|
2013-03-11 08:44:53 +00:00
|
|
|
|
|
|
|
/* Reset USB hub */
|
|
|
|
gpio_direction_output(IMX_GPIO_NR(7, 12), 0);
|
|
|
|
mdelay(2);
|
|
|
|
gpio_set_value(IMX_GPIO_NR(7, 12), 1);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2013-09-26 01:41:17 +00:00
|
|
|
|
|
|
|
int board_ehci_power(int port, int on)
|
|
|
|
{
|
|
|
|
if (port)
|
|
|
|
return 0;
|
|
|
|
gpio_set_value(GP_USB_OTG_PWR, on);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-03-11 08:44:53 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef CONFIG_MXC_SPI
|
spi: mxc: fix sf probe when using mxc_spi
MXC SPI driver has a feature whereas a GPIO line can be used to force CS high
across multiple transactions. This is set up by embedding the GPIO information
in the CS value:
cs = (cs | gpio << 8)
This merge of cs and gpio data into one value breaks the sf probe command:
if the use of gpio is required, invoking "sf probe <cs>" will not work, because
the CS argument doesn't have the GPIO information in it. Instead, the user must
use "sf probe <cs | gpio << 8>". For example, if bank 2 gpio 30 is used to force
cs high on cs 0, bus 0, then instead of typing "sf probe 0" the user now must
type "sf probe 15872".
This is inconsistent with the description of the sf probe command, and forces
the user to be aware of implementaiton details.
Fix this by introducing a new board function: board_spi_cs_gpio(), which will
accept a naked CS value, and provide the driver with the relevant GPIO, if one
is necessary.
Cc: Eric Nelson <eric.nelson@boundarydevices.com>
Cc: Eric Benard <eric@eukrea.com>
Cc: Fabio Estevam <fabio.estevam@freescale.com>
Cc: Tim Harvey <tharvey@gateworks.com>
Cc: Stefano Babic <sbabic@denx.de>
Cc: Tom Rini <trini@ti.com>
Cc: Marek Vasut <marex@denx.de>
Reviewed-by: Marek Vasut <marex@denx.de>
Signed-off-by: Nikita Kiryanov <nikita@compulab.co.il>
Reviewed-by: Jagannadha Sutradharudu Teki <jaganna@xilinx.com>
2014-08-20 12:08:50 +00:00
|
|
|
int board_spi_cs_gpio(unsigned bus, unsigned cs)
|
|
|
|
{
|
|
|
|
return (bus == 0 && cs == 0) ? (IMX_GPIO_NR(3, 19)) : -1;
|
|
|
|
}
|
|
|
|
|
2014-10-02 19:16:27 +00:00
|
|
|
static iomux_v3_cfg_t const ecspi1_pads[] = {
|
2013-03-11 08:44:53 +00:00
|
|
|
/* SS1 */
|
2019-11-04 02:20:04 +00:00
|
|
|
IOMUX_PAD_CTRL(EIM_D19__GPIO3_IO19, NO_PAD_CTRL),
|
|
|
|
IOMUX_PAD_CTRL(EIM_D17__ECSPI1_MISO, SPI_PAD_CTRL),
|
|
|
|
IOMUX_PAD_CTRL(EIM_D18__ECSPI1_MOSI, SPI_PAD_CTRL),
|
|
|
|
IOMUX_PAD_CTRL(EIM_D16__ECSPI1_SCLK, SPI_PAD_CTRL),
|
2013-03-11 08:44:53 +00:00
|
|
|
};
|
|
|
|
|
2014-10-02 19:16:27 +00:00
|
|
|
static void setup_spi(void)
|
2013-03-11 08:44:53 +00:00
|
|
|
{
|
2019-11-04 02:20:04 +00:00
|
|
|
SETUP_IOMUX_PADS(ecspi1_pads);
|
2013-03-11 08:44:53 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
int board_phy_config(struct phy_device *phydev)
|
|
|
|
{
|
|
|
|
/* min rx data delay */
|
|
|
|
ksz9021_phy_extended_write(phydev,
|
|
|
|
MII_KSZ9021_EXT_RGMII_RX_DATA_SKEW, 0x0);
|
|
|
|
/* min tx data delay */
|
|
|
|
ksz9021_phy_extended_write(phydev,
|
|
|
|
MII_KSZ9021_EXT_RGMII_TX_DATA_SKEW, 0x0);
|
|
|
|
/* max rx/tx clock delay, min rx/tx control */
|
|
|
|
ksz9021_phy_extended_write(phydev,
|
|
|
|
MII_KSZ9021_EXT_RGMII_CLOCK_SKEW, 0xf0f0);
|
|
|
|
if (phydev->drv->config)
|
|
|
|
phydev->drv->config(phydev);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-06-26 06:13:33 +00:00
|
|
|
int board_eth_init(struct bd_info *bis)
|
2013-03-11 08:44:53 +00:00
|
|
|
{
|
|
|
|
uint32_t base = IMX_FEC_BASE;
|
|
|
|
struct mii_dev *bus = NULL;
|
|
|
|
struct phy_device *phydev = NULL;
|
|
|
|
int ret;
|
|
|
|
|
2019-07-29 19:15:56 +00:00
|
|
|
gpio_request(WL12XX_WL_IRQ_GP, "wifi_irq");
|
|
|
|
gpio_request(IMX_GPIO_NR(6, 30), "rgmii_rxc");
|
|
|
|
gpio_request(IMX_GPIO_NR(6, 25), "rgmii_rd0");
|
|
|
|
gpio_request(IMX_GPIO_NR(6, 27), "rgmii_rd1");
|
|
|
|
gpio_request(IMX_GPIO_NR(6, 28), "rgmii_rd2");
|
|
|
|
gpio_request(IMX_GPIO_NR(6, 29), "rgmii_rd3");
|
|
|
|
gpio_request(IMX_GPIO_NR(6, 24), "rgmii_rx_ctl");
|
|
|
|
gpio_request(IMX_GPIO_NR(3, 23), "rgmii_reset_sabrelite");
|
|
|
|
gpio_request(IMX_GPIO_NR(1, 27), "rgmii_reset_nitrogen6x");
|
2013-03-11 08:44:53 +00:00
|
|
|
setup_iomux_enet();
|
|
|
|
|
|
|
|
#ifdef CONFIG_FEC_MXC
|
|
|
|
bus = fec_get_miibus(base, -1);
|
|
|
|
if (!bus)
|
2015-09-11 03:53:51 +00:00
|
|
|
return -EINVAL;
|
2013-03-11 08:44:53 +00:00
|
|
|
/* scan phy 4,5,6,7 */
|
|
|
|
phydev = phy_find_by_mask(bus, (0xf << 4), PHY_INTERFACE_MODE_RGMII);
|
|
|
|
if (!phydev) {
|
2015-09-11 03:53:51 +00:00
|
|
|
ret = -EINVAL;
|
|
|
|
goto free_bus;
|
2013-03-11 08:44:53 +00:00
|
|
|
}
|
|
|
|
printf("using phy at %d\n", phydev->addr);
|
|
|
|
ret = fec_probe(bis, -1, base, bus, phydev);
|
2015-09-11 03:53:51 +00:00
|
|
|
if (ret)
|
|
|
|
goto free_phydev;
|
2013-03-11 08:44:53 +00:00
|
|
|
#endif
|
2013-09-26 01:41:17 +00:00
|
|
|
|
2014-02-06 01:43:45 +00:00
|
|
|
#ifdef CONFIG_CI_UDC
|
2013-09-26 01:41:17 +00:00
|
|
|
/* For otg ethernet*/
|
|
|
|
usb_eth_initialize(bis);
|
|
|
|
#endif
|
2013-03-11 08:44:53 +00:00
|
|
|
return 0;
|
2015-09-11 03:53:51 +00:00
|
|
|
|
|
|
|
free_phydev:
|
|
|
|
free(phydev);
|
|
|
|
free_bus:
|
|
|
|
free(bus);
|
|
|
|
return ret;
|
2013-03-11 08:44:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void setup_buttons(void)
|
|
|
|
{
|
2019-11-04 02:20:04 +00:00
|
|
|
SETUP_IOMUX_PADS(button_pads);
|
2013-03-11 08:44:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(CONFIG_VIDEO_IPUV3)
|
|
|
|
|
|
|
|
static iomux_v3_cfg_t const backlight_pads[] = {
|
|
|
|
/* Backlight on RGB connector: J15 */
|
2019-11-04 02:20:04 +00:00
|
|
|
IOMUX_PAD_CTRL(SD1_DAT3__GPIO1_IO21, NO_PAD_CTRL),
|
2013-03-11 08:44:53 +00:00
|
|
|
#define RGB_BACKLIGHT_GP IMX_GPIO_NR(1, 21)
|
|
|
|
|
|
|
|
/* Backlight on LVDS connector: J6 */
|
2019-11-04 02:20:04 +00:00
|
|
|
IOMUX_PAD_CTRL(SD1_CMD__GPIO1_IO18, NO_PAD_CTRL),
|
2013-03-11 08:44:53 +00:00
|
|
|
#define LVDS_BACKLIGHT_GP IMX_GPIO_NR(1, 18)
|
|
|
|
};
|
|
|
|
|
|
|
|
static iomux_v3_cfg_t const rgb_pads[] = {
|
2019-11-04 02:20:04 +00:00
|
|
|
IOMUX_PAD_CTRL(DI0_DISP_CLK__IPU1_DI0_DISP_CLK, RGB_PAD_CTRL),
|
|
|
|
IOMUX_PAD_CTRL(DI0_PIN15__IPU1_DI0_PIN15, RGB_PAD_CTRL),
|
|
|
|
IOMUX_PAD_CTRL(DI0_PIN2__IPU1_DI0_PIN02, RGB_PAD_CTRL),
|
|
|
|
IOMUX_PAD_CTRL(DI0_PIN3__IPU1_DI0_PIN03, RGB_PAD_CTRL),
|
|
|
|
IOMUX_PAD_CTRL(DI0_PIN4__GPIO4_IO20, RGB_PAD_CTRL),
|
|
|
|
IOMUX_PAD_CTRL(DISP0_DAT0__IPU1_DISP0_DATA00, RGB_PAD_CTRL),
|
|
|
|
IOMUX_PAD_CTRL(DISP0_DAT1__IPU1_DISP0_DATA01, RGB_PAD_CTRL),
|
|
|
|
IOMUX_PAD_CTRL(DISP0_DAT2__IPU1_DISP0_DATA02, RGB_PAD_CTRL),
|
|
|
|
IOMUX_PAD_CTRL(DISP0_DAT3__IPU1_DISP0_DATA03, RGB_PAD_CTRL),
|
|
|
|
IOMUX_PAD_CTRL(DISP0_DAT4__IPU1_DISP0_DATA04, RGB_PAD_CTRL),
|
|
|
|
IOMUX_PAD_CTRL(DISP0_DAT5__IPU1_DISP0_DATA05, RGB_PAD_CTRL),
|
|
|
|
IOMUX_PAD_CTRL(DISP0_DAT6__IPU1_DISP0_DATA06, RGB_PAD_CTRL),
|
|
|
|
IOMUX_PAD_CTRL(DISP0_DAT7__IPU1_DISP0_DATA07, RGB_PAD_CTRL),
|
|
|
|
IOMUX_PAD_CTRL(DISP0_DAT8__IPU1_DISP0_DATA08, RGB_PAD_CTRL),
|
|
|
|
IOMUX_PAD_CTRL(DISP0_DAT9__IPU1_DISP0_DATA09, RGB_PAD_CTRL),
|
|
|
|
IOMUX_PAD_CTRL(DISP0_DAT10__IPU1_DISP0_DATA10, RGB_PAD_CTRL),
|
|
|
|
IOMUX_PAD_CTRL(DISP0_DAT11__IPU1_DISP0_DATA11, RGB_PAD_CTRL),
|
|
|
|
IOMUX_PAD_CTRL(DISP0_DAT12__IPU1_DISP0_DATA12, RGB_PAD_CTRL),
|
|
|
|
IOMUX_PAD_CTRL(DISP0_DAT13__IPU1_DISP0_DATA13, RGB_PAD_CTRL),
|
|
|
|
IOMUX_PAD_CTRL(DISP0_DAT14__IPU1_DISP0_DATA14, RGB_PAD_CTRL),
|
|
|
|
IOMUX_PAD_CTRL(DISP0_DAT15__IPU1_DISP0_DATA15, RGB_PAD_CTRL),
|
|
|
|
IOMUX_PAD_CTRL(DISP0_DAT16__IPU1_DISP0_DATA16, RGB_PAD_CTRL),
|
|
|
|
IOMUX_PAD_CTRL(DISP0_DAT17__IPU1_DISP0_DATA17, RGB_PAD_CTRL),
|
|
|
|
IOMUX_PAD_CTRL(DISP0_DAT18__IPU1_DISP0_DATA18, RGB_PAD_CTRL),
|
|
|
|
IOMUX_PAD_CTRL(DISP0_DAT19__IPU1_DISP0_DATA19, RGB_PAD_CTRL),
|
|
|
|
IOMUX_PAD_CTRL(DISP0_DAT20__IPU1_DISP0_DATA20, RGB_PAD_CTRL),
|
|
|
|
IOMUX_PAD_CTRL(DISP0_DAT21__IPU1_DISP0_DATA21, RGB_PAD_CTRL),
|
|
|
|
IOMUX_PAD_CTRL(DISP0_DAT22__IPU1_DISP0_DATA22, RGB_PAD_CTRL),
|
|
|
|
IOMUX_PAD_CTRL(DISP0_DAT23__IPU1_DISP0_DATA23, RGB_PAD_CTRL),
|
2013-03-11 08:44:53 +00:00
|
|
|
};
|
|
|
|
|
2013-07-25 17:12:13 +00:00
|
|
|
static void do_enable_hdmi(struct display_info_t const *dev)
|
2013-03-11 08:44:53 +00:00
|
|
|
{
|
2013-07-25 17:12:13 +00:00
|
|
|
imx_enable_hdmi_phy();
|
2013-03-11 08:44:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int detect_i2c(struct display_info_t const *dev)
|
|
|
|
{
|
|
|
|
return ((0 == i2c_set_bus_num(dev->bus))
|
|
|
|
&&
|
|
|
|
(0 == i2c_probe(dev->addr)));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void enable_lvds(struct display_info_t const *dev)
|
|
|
|
{
|
|
|
|
struct iomuxc *iomux = (struct iomuxc *)
|
|
|
|
IOMUXC_BASE_ADDR;
|
|
|
|
u32 reg = readl(&iomux->gpr[2]);
|
|
|
|
reg |= IOMUXC_GPR2_DATA_WIDTH_CH0_24BIT;
|
|
|
|
writel(reg, &iomux->gpr[2]);
|
|
|
|
gpio_direction_output(LVDS_BACKLIGHT_GP, 1);
|
|
|
|
}
|
|
|
|
|
2014-10-02 19:16:31 +00:00
|
|
|
static void enable_lvds_jeida(struct display_info_t const *dev)
|
|
|
|
{
|
|
|
|
struct iomuxc *iomux = (struct iomuxc *)
|
|
|
|
IOMUXC_BASE_ADDR;
|
|
|
|
u32 reg = readl(&iomux->gpr[2]);
|
|
|
|
reg |= IOMUXC_GPR2_DATA_WIDTH_CH0_24BIT
|
|
|
|
|IOMUXC_GPR2_BIT_MAPPING_CH0_JEIDA;
|
|
|
|
writel(reg, &iomux->gpr[2]);
|
|
|
|
gpio_direction_output(LVDS_BACKLIGHT_GP, 1);
|
|
|
|
}
|
|
|
|
|
2013-03-11 08:44:53 +00:00
|
|
|
static void enable_rgb(struct display_info_t const *dev)
|
|
|
|
{
|
2019-11-04 02:20:04 +00:00
|
|
|
SETUP_IOMUX_PADS(rgb_pads);
|
2013-03-11 08:44:53 +00:00
|
|
|
gpio_direction_output(RGB_BACKLIGHT_GP, 1);
|
|
|
|
}
|
|
|
|
|
2014-04-04 17:05:53 +00:00
|
|
|
struct display_info_t const displays[] = {{
|
2014-10-02 19:16:39 +00:00
|
|
|
.bus = 1,
|
|
|
|
.addr = 0x50,
|
2013-03-11 08:44:53 +00:00
|
|
|
.pixfmt = IPU_PIX_FMT_RGB24,
|
2014-10-02 19:16:39 +00:00
|
|
|
.detect = detect_i2c,
|
2013-07-25 17:12:13 +00:00
|
|
|
.enable = do_enable_hdmi,
|
2013-03-11 08:44:53 +00:00
|
|
|
.mode = {
|
|
|
|
.name = "HDMI",
|
|
|
|
.refresh = 60,
|
|
|
|
.xres = 1024,
|
|
|
|
.yres = 768,
|
|
|
|
.pixclock = 15385,
|
|
|
|
.left_margin = 220,
|
|
|
|
.right_margin = 40,
|
|
|
|
.upper_margin = 21,
|
|
|
|
.lower_margin = 7,
|
|
|
|
.hsync_len = 60,
|
|
|
|
.vsync_len = 10,
|
|
|
|
.sync = FB_SYNC_EXT,
|
|
|
|
.vmode = FB_VMODE_NONINTERLACED
|
2014-10-02 19:16:31 +00:00
|
|
|
} }, {
|
|
|
|
.bus = 0,
|
|
|
|
.addr = 0,
|
|
|
|
.pixfmt = IPU_PIX_FMT_RGB24,
|
|
|
|
.detect = NULL,
|
|
|
|
.enable = enable_lvds_jeida,
|
|
|
|
.mode = {
|
|
|
|
.name = "LDB-WXGA",
|
|
|
|
.refresh = 60,
|
|
|
|
.xres = 1280,
|
|
|
|
.yres = 800,
|
|
|
|
.pixclock = 14065,
|
|
|
|
.left_margin = 40,
|
|
|
|
.right_margin = 40,
|
|
|
|
.upper_margin = 3,
|
|
|
|
.lower_margin = 80,
|
|
|
|
.hsync_len = 10,
|
|
|
|
.vsync_len = 10,
|
|
|
|
.sync = FB_SYNC_EXT,
|
|
|
|
.vmode = FB_VMODE_NONINTERLACED
|
2014-10-02 19:16:34 +00:00
|
|
|
} }, {
|
|
|
|
.bus = 0,
|
|
|
|
.addr = 0,
|
|
|
|
.pixfmt = IPU_PIX_FMT_RGB24,
|
|
|
|
.detect = NULL,
|
|
|
|
.enable = enable_lvds,
|
|
|
|
.mode = {
|
|
|
|
.name = "LDB-WXGA-S",
|
|
|
|
.refresh = 60,
|
|
|
|
.xres = 1280,
|
|
|
|
.yres = 800,
|
|
|
|
.pixclock = 14065,
|
|
|
|
.left_margin = 40,
|
|
|
|
.right_margin = 40,
|
|
|
|
.upper_margin = 3,
|
|
|
|
.lower_margin = 80,
|
|
|
|
.hsync_len = 10,
|
|
|
|
.vsync_len = 10,
|
|
|
|
.sync = FB_SYNC_EXT,
|
|
|
|
.vmode = FB_VMODE_NONINTERLACED
|
2013-03-11 08:44:53 +00:00
|
|
|
} }, {
|
|
|
|
.bus = 2,
|
|
|
|
.addr = 0x4,
|
|
|
|
.pixfmt = IPU_PIX_FMT_LVDS666,
|
|
|
|
.detect = detect_i2c,
|
|
|
|
.enable = enable_lvds,
|
|
|
|
.mode = {
|
|
|
|
.name = "Hannstar-XGA",
|
|
|
|
.refresh = 60,
|
|
|
|
.xres = 1024,
|
|
|
|
.yres = 768,
|
|
|
|
.pixclock = 15385,
|
|
|
|
.left_margin = 220,
|
|
|
|
.right_margin = 40,
|
|
|
|
.upper_margin = 21,
|
|
|
|
.lower_margin = 7,
|
|
|
|
.hsync_len = 60,
|
|
|
|
.vsync_len = 10,
|
|
|
|
.sync = FB_SYNC_EXT,
|
|
|
|
.vmode = FB_VMODE_NONINTERLACED
|
2014-10-02 19:16:33 +00:00
|
|
|
} }, {
|
|
|
|
.bus = 0,
|
|
|
|
.addr = 0,
|
|
|
|
.pixfmt = IPU_PIX_FMT_LVDS666,
|
|
|
|
.detect = NULL,
|
|
|
|
.enable = enable_lvds,
|
|
|
|
.mode = {
|
|
|
|
.name = "LG-9.7",
|
|
|
|
.refresh = 60,
|
|
|
|
.xres = 1024,
|
|
|
|
.yres = 768,
|
|
|
|
.pixclock = 15385, /* ~65MHz */
|
|
|
|
.left_margin = 480,
|
|
|
|
.right_margin = 260,
|
|
|
|
.upper_margin = 16,
|
|
|
|
.lower_margin = 6,
|
|
|
|
.hsync_len = 250,
|
|
|
|
.vsync_len = 10,
|
|
|
|
.sync = FB_SYNC_EXT,
|
|
|
|
.vmode = FB_VMODE_NONINTERLACED
|
2013-03-11 08:44:53 +00:00
|
|
|
} }, {
|
|
|
|
.bus = 2,
|
|
|
|
.addr = 0x38,
|
|
|
|
.pixfmt = IPU_PIX_FMT_LVDS666,
|
|
|
|
.detect = detect_i2c,
|
|
|
|
.enable = enable_lvds,
|
|
|
|
.mode = {
|
|
|
|
.name = "wsvga-lvds",
|
|
|
|
.refresh = 60,
|
|
|
|
.xres = 1024,
|
|
|
|
.yres = 600,
|
|
|
|
.pixclock = 15385,
|
|
|
|
.left_margin = 220,
|
|
|
|
.right_margin = 40,
|
|
|
|
.upper_margin = 21,
|
|
|
|
.lower_margin = 7,
|
|
|
|
.hsync_len = 60,
|
|
|
|
.vsync_len = 10,
|
|
|
|
.sync = FB_SYNC_EXT,
|
|
|
|
.vmode = FB_VMODE_NONINTERLACED
|
2014-10-02 19:16:35 +00:00
|
|
|
} }, {
|
|
|
|
.bus = 2,
|
|
|
|
.addr = 0x10,
|
|
|
|
.pixfmt = IPU_PIX_FMT_RGB666,
|
|
|
|
.detect = detect_i2c,
|
|
|
|
.enable = enable_rgb,
|
|
|
|
.mode = {
|
|
|
|
.name = "fusion7",
|
|
|
|
.refresh = 60,
|
|
|
|
.xres = 800,
|
|
|
|
.yres = 480,
|
|
|
|
.pixclock = 33898,
|
|
|
|
.left_margin = 96,
|
|
|
|
.right_margin = 24,
|
|
|
|
.upper_margin = 3,
|
|
|
|
.lower_margin = 10,
|
|
|
|
.hsync_len = 72,
|
|
|
|
.vsync_len = 7,
|
|
|
|
.sync = 0x40000002,
|
|
|
|
.vmode = FB_VMODE_NONINTERLACED
|
2014-10-02 19:16:36 +00:00
|
|
|
} }, {
|
|
|
|
.bus = 0,
|
|
|
|
.addr = 0,
|
|
|
|
.pixfmt = IPU_PIX_FMT_RGB666,
|
|
|
|
.detect = NULL,
|
|
|
|
.enable = enable_rgb,
|
|
|
|
.mode = {
|
|
|
|
.name = "svga",
|
|
|
|
.refresh = 60,
|
|
|
|
.xres = 800,
|
|
|
|
.yres = 600,
|
|
|
|
.pixclock = 15385,
|
|
|
|
.left_margin = 220,
|
|
|
|
.right_margin = 40,
|
|
|
|
.upper_margin = 21,
|
|
|
|
.lower_margin = 7,
|
|
|
|
.hsync_len = 60,
|
|
|
|
.vsync_len = 10,
|
|
|
|
.sync = 0,
|
|
|
|
.vmode = FB_VMODE_NONINTERLACED
|
2014-10-02 19:16:37 +00:00
|
|
|
} }, {
|
|
|
|
.bus = 2,
|
|
|
|
.addr = 0x41,
|
|
|
|
.pixfmt = IPU_PIX_FMT_LVDS666,
|
|
|
|
.detect = detect_i2c,
|
|
|
|
.enable = enable_lvds,
|
|
|
|
.mode = {
|
|
|
|
.name = "amp1024x600",
|
|
|
|
.refresh = 60,
|
|
|
|
.xres = 1024,
|
|
|
|
.yres = 600,
|
|
|
|
.pixclock = 15385,
|
|
|
|
.left_margin = 220,
|
|
|
|
.right_margin = 40,
|
|
|
|
.upper_margin = 21,
|
|
|
|
.lower_margin = 7,
|
|
|
|
.hsync_len = 60,
|
|
|
|
.vsync_len = 10,
|
|
|
|
.sync = FB_SYNC_EXT,
|
|
|
|
.vmode = FB_VMODE_NONINTERLACED
|
2014-10-02 19:16:38 +00:00
|
|
|
} }, {
|
|
|
|
.bus = 0,
|
|
|
|
.addr = 0,
|
|
|
|
.pixfmt = IPU_PIX_FMT_LVDS666,
|
|
|
|
.detect = 0,
|
|
|
|
.enable = enable_lvds,
|
|
|
|
.mode = {
|
|
|
|
.name = "wvga-lvds",
|
|
|
|
.refresh = 57,
|
|
|
|
.xres = 800,
|
|
|
|
.yres = 480,
|
|
|
|
.pixclock = 15385,
|
|
|
|
.left_margin = 220,
|
|
|
|
.right_margin = 40,
|
|
|
|
.upper_margin = 21,
|
|
|
|
.lower_margin = 7,
|
|
|
|
.hsync_len = 60,
|
|
|
|
.vsync_len = 10,
|
|
|
|
.sync = FB_SYNC_EXT,
|
|
|
|
.vmode = FB_VMODE_NONINTERLACED
|
2013-03-11 08:44:53 +00:00
|
|
|
} }, {
|
|
|
|
.bus = 2,
|
|
|
|
.addr = 0x48,
|
|
|
|
.pixfmt = IPU_PIX_FMT_RGB666,
|
|
|
|
.detect = detect_i2c,
|
|
|
|
.enable = enable_rgb,
|
|
|
|
.mode = {
|
|
|
|
.name = "wvga-rgb",
|
|
|
|
.refresh = 57,
|
|
|
|
.xres = 800,
|
|
|
|
.yres = 480,
|
|
|
|
.pixclock = 37037,
|
|
|
|
.left_margin = 40,
|
|
|
|
.right_margin = 60,
|
|
|
|
.upper_margin = 10,
|
|
|
|
.lower_margin = 10,
|
|
|
|
.hsync_len = 20,
|
|
|
|
.vsync_len = 10,
|
|
|
|
.sync = 0,
|
|
|
|
.vmode = FB_VMODE_NONINTERLACED
|
2014-10-02 19:16:32 +00:00
|
|
|
} }, {
|
|
|
|
.bus = 0,
|
|
|
|
.addr = 0,
|
|
|
|
.pixfmt = IPU_PIX_FMT_RGB24,
|
|
|
|
.detect = NULL,
|
|
|
|
.enable = enable_rgb,
|
|
|
|
.mode = {
|
|
|
|
.name = "qvga",
|
|
|
|
.refresh = 60,
|
|
|
|
.xres = 320,
|
|
|
|
.yres = 240,
|
|
|
|
.pixclock = 37037,
|
|
|
|
.left_margin = 38,
|
|
|
|
.right_margin = 37,
|
|
|
|
.upper_margin = 16,
|
|
|
|
.lower_margin = 15,
|
|
|
|
.hsync_len = 30,
|
|
|
|
.vsync_len = 3,
|
|
|
|
.sync = 0,
|
|
|
|
.vmode = FB_VMODE_NONINTERLACED
|
2013-03-11 08:44:53 +00:00
|
|
|
} } };
|
2014-04-04 17:05:53 +00:00
|
|
|
size_t display_count = ARRAY_SIZE(displays);
|
2013-03-11 08:44:53 +00:00
|
|
|
|
2014-10-02 19:16:22 +00:00
|
|
|
int board_cfb_skip(void)
|
|
|
|
{
|
2017-08-03 18:22:12 +00:00
|
|
|
return NULL != env_get("novideo");
|
2014-10-02 19:16:22 +00:00
|
|
|
}
|
|
|
|
|
2013-03-11 08:44:53 +00:00
|
|
|
static void setup_display(void)
|
|
|
|
{
|
|
|
|
struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
|
|
|
|
struct iomuxc *iomux = (struct iomuxc *)IOMUXC_BASE_ADDR;
|
|
|
|
int reg;
|
|
|
|
|
2013-07-25 17:12:13 +00:00
|
|
|
enable_ipu_clock();
|
|
|
|
imx_setup_hdmi();
|
2013-03-11 08:44:53 +00:00
|
|
|
/* Turn on LDB0,IPU,IPU DI0 clocks */
|
|
|
|
reg = __raw_readl(&mxc_ccm->CCGR3);
|
2013-07-25 17:12:13 +00:00
|
|
|
reg |= MXC_CCM_CCGR3_LDB_DI0_MASK;
|
2013-03-11 08:44:53 +00:00
|
|
|
writel(reg, &mxc_ccm->CCGR3);
|
|
|
|
|
|
|
|
/* set LDB0, LDB1 clk select to 011/011 */
|
|
|
|
reg = readl(&mxc_ccm->cs2cdr);
|
|
|
|
reg &= ~(MXC_CCM_CS2CDR_LDB_DI0_CLK_SEL_MASK
|
|
|
|
|MXC_CCM_CS2CDR_LDB_DI1_CLK_SEL_MASK);
|
|
|
|
reg |= (3<<MXC_CCM_CS2CDR_LDB_DI0_CLK_SEL_OFFSET)
|
|
|
|
|(3<<MXC_CCM_CS2CDR_LDB_DI1_CLK_SEL_OFFSET);
|
|
|
|
writel(reg, &mxc_ccm->cs2cdr);
|
|
|
|
|
|
|
|
reg = readl(&mxc_ccm->cscmr2);
|
|
|
|
reg |= MXC_CCM_CSCMR2_LDB_DI0_IPU_DIV;
|
|
|
|
writel(reg, &mxc_ccm->cscmr2);
|
|
|
|
|
|
|
|
reg = readl(&mxc_ccm->chsccdr);
|
|
|
|
reg |= (CHSCCDR_CLK_SEL_LDB_DI0
|
2013-07-25 17:12:13 +00:00
|
|
|
<<MXC_CCM_CHSCCDR_IPU1_DI0_CLK_SEL_OFFSET);
|
2013-03-11 08:44:53 +00:00
|
|
|
writel(reg, &mxc_ccm->chsccdr);
|
|
|
|
|
|
|
|
reg = IOMUXC_GPR2_BGREF_RRMODE_EXTERNAL_RES
|
|
|
|
|IOMUXC_GPR2_DI1_VS_POLARITY_ACTIVE_HIGH
|
|
|
|
|IOMUXC_GPR2_DI0_VS_POLARITY_ACTIVE_LOW
|
|
|
|
|IOMUXC_GPR2_BIT_MAPPING_CH1_SPWG
|
|
|
|
|IOMUXC_GPR2_DATA_WIDTH_CH1_18BIT
|
|
|
|
|IOMUXC_GPR2_BIT_MAPPING_CH0_SPWG
|
|
|
|
|IOMUXC_GPR2_DATA_WIDTH_CH0_18BIT
|
|
|
|
|IOMUXC_GPR2_LVDS_CH1_MODE_DISABLED
|
|
|
|
|IOMUXC_GPR2_LVDS_CH0_MODE_ENABLED_DI0;
|
|
|
|
writel(reg, &iomux->gpr[2]);
|
|
|
|
|
|
|
|
reg = readl(&iomux->gpr[3]);
|
2013-08-20 18:44:43 +00:00
|
|
|
reg = (reg & ~(IOMUXC_GPR3_LVDS0_MUX_CTL_MASK
|
|
|
|
|IOMUXC_GPR3_HDMI_MUX_CTL_MASK))
|
2013-03-11 08:44:53 +00:00
|
|
|
| (IOMUXC_GPR3_MUX_SRC_IPU1_DI0
|
|
|
|
<<IOMUXC_GPR3_LVDS0_MUX_CTL_OFFSET);
|
|
|
|
writel(reg, &iomux->gpr[3]);
|
|
|
|
|
|
|
|
/* backlights off until needed */
|
2019-11-04 02:20:04 +00:00
|
|
|
SETUP_IOMUX_PADS(backlight_pads);
|
2013-03-11 08:44:53 +00:00
|
|
|
gpio_direction_input(LVDS_BACKLIGHT_GP);
|
|
|
|
gpio_direction_input(RGB_BACKLIGHT_GP);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2014-10-02 19:16:25 +00:00
|
|
|
static iomux_v3_cfg_t const init_pads[] = {
|
2014-10-02 19:16:26 +00:00
|
|
|
/* SGTL5000 sys_mclk */
|
2019-11-04 02:20:04 +00:00
|
|
|
IOMUX_PAD_CTRL(GPIO_0__CCM_CLKO1, OUTPUT_40OHM),
|
2014-10-02 19:16:26 +00:00
|
|
|
|
|
|
|
/* J5 - Camera MCLK */
|
2019-11-04 02:20:04 +00:00
|
|
|
IOMUX_PAD_CTRL(GPIO_3__CCM_CLKO2, OUTPUT_40OHM),
|
2014-10-02 19:16:26 +00:00
|
|
|
|
|
|
|
/* wl1271 pads on nitrogen6x */
|
2014-10-02 19:16:25 +00:00
|
|
|
/* WL12XX_WL_IRQ_GP */
|
2019-11-04 02:20:04 +00:00
|
|
|
IOMUX_PAD_CTRL(NANDF_CS1__GPIO6_IO14, WEAK_PULLDOWN),
|
2014-10-02 19:16:25 +00:00
|
|
|
/* WL12XX_WL_ENABLE_GP */
|
2019-11-04 02:20:04 +00:00
|
|
|
IOMUX_PAD_CTRL(NANDF_CS2__GPIO6_IO15, OUTPUT_40OHM),
|
2014-10-02 19:16:25 +00:00
|
|
|
/* WL12XX_BT_ENABLE_GP */
|
2019-11-04 02:20:04 +00:00
|
|
|
IOMUX_PAD_CTRL(NANDF_CS3__GPIO6_IO16, OUTPUT_40OHM),
|
2014-10-02 19:16:25 +00:00
|
|
|
/* USB otg power */
|
2019-11-04 02:20:04 +00:00
|
|
|
IOMUX_PAD_CTRL(EIM_D22__GPIO3_IO22, OUTPUT_40OHM),
|
|
|
|
IOMUX_PAD_CTRL(NANDF_D5__GPIO2_IO05, OUTPUT_40OHM),
|
|
|
|
IOMUX_PAD_CTRL(NANDF_WP_B__GPIO6_IO09, OUTPUT_40OHM),
|
|
|
|
IOMUX_PAD_CTRL(GPIO_8__GPIO1_IO08, OUTPUT_40OHM),
|
|
|
|
IOMUX_PAD_CTRL(GPIO_6__GPIO1_IO06, OUTPUT_40OHM),
|
2014-10-02 19:16:25 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
#define WL12XX_WL_IRQ_GP IMX_GPIO_NR(6, 14)
|
|
|
|
|
|
|
|
static unsigned gpios_out_low[] = {
|
|
|
|
/* Disable wl1271 */
|
|
|
|
IMX_GPIO_NR(6, 15), /* disable wireless */
|
|
|
|
IMX_GPIO_NR(6, 16), /* disable bluetooth */
|
|
|
|
IMX_GPIO_NR(3, 22), /* disable USB otg power */
|
|
|
|
IMX_GPIO_NR(2, 5), /* ov5640 mipi camera reset */
|
|
|
|
IMX_GPIO_NR(1, 8), /* ov5642 reset */
|
|
|
|
};
|
|
|
|
|
|
|
|
static unsigned gpios_out_high[] = {
|
|
|
|
IMX_GPIO_NR(1, 6), /* ov5642 powerdown */
|
|
|
|
IMX_GPIO_NR(6, 9), /* ov5640 mipi camera power down */
|
|
|
|
};
|
|
|
|
|
|
|
|
static void set_gpios(unsigned *p, int cnt, int val)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < cnt; i++)
|
|
|
|
gpio_direction_output(*p++, val);
|
|
|
|
}
|
|
|
|
|
2013-03-11 08:44:53 +00:00
|
|
|
int board_early_init_f(void)
|
|
|
|
{
|
|
|
|
setup_iomux_uart();
|
|
|
|
|
2014-10-02 19:16:25 +00:00
|
|
|
set_gpios(gpios_out_high, ARRAY_SIZE(gpios_out_high), 1);
|
|
|
|
set_gpios(gpios_out_low, ARRAY_SIZE(gpios_out_low), 0);
|
2013-03-11 08:44:53 +00:00
|
|
|
gpio_direction_input(WL12XX_WL_IRQ_GP);
|
|
|
|
|
2019-11-04 02:20:04 +00:00
|
|
|
SETUP_IOMUX_PADS(wl12xx_pads);
|
|
|
|
SETUP_IOMUX_PADS(init_pads);
|
2013-03-11 08:44:53 +00:00
|
|
|
setup_buttons();
|
|
|
|
|
|
|
|
#if defined(CONFIG_VIDEO_IPUV3)
|
|
|
|
setup_display();
|
|
|
|
#endif
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Do not overwrite the console
|
|
|
|
* Use always serial for U-Boot console
|
|
|
|
*/
|
|
|
|
int overwrite_console(void)
|
|
|
|
{
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int board_init(void)
|
|
|
|
{
|
2014-07-09 20:59:54 +00:00
|
|
|
struct iomuxc *const iomuxc_regs = (struct iomuxc *)IOMUXC_BASE_ADDR;
|
2019-11-04 02:20:04 +00:00
|
|
|
struct i2c_pads_info *p = i2c_pads;
|
|
|
|
int i;
|
|
|
|
int stride = 1;
|
2013-09-26 01:41:16 +00:00
|
|
|
|
2019-11-04 02:20:04 +00:00
|
|
|
#if defined(CONFIG_MX6QDL)
|
|
|
|
stride = 2;
|
|
|
|
if (!is_mx6dq() && !is_mx6dqp())
|
|
|
|
p += 1;
|
|
|
|
#endif
|
2013-09-26 01:41:16 +00:00
|
|
|
clrsetbits_le32(&iomuxc_regs->gpr[1],
|
|
|
|
IOMUXC_GPR1_OTG_ID_MASK,
|
|
|
|
IOMUXC_GPR1_OTG_ID_GPIO1);
|
|
|
|
|
2019-11-04 02:20:04 +00:00
|
|
|
SETUP_IOMUX_PADS(misc_pads);
|
2013-09-26 01:41:17 +00:00
|
|
|
|
2013-03-11 08:44:53 +00:00
|
|
|
/* address of boot parameters */
|
|
|
|
gd->bd->bi_boot_params = PHYS_SDRAM + 0x100;
|
|
|
|
|
|
|
|
#ifdef CONFIG_MXC_SPI
|
|
|
|
setup_spi();
|
|
|
|
#endif
|
2019-11-04 02:20:04 +00:00
|
|
|
SETUP_IOMUX_PADS(usdhc2_pads);
|
|
|
|
for (i = 0; i < I2C_BUS_CNT; i++) {
|
|
|
|
setup_i2c(i, CONFIG_SYS_I2C_SPEED, 0x7f, p);
|
|
|
|
p += stride;
|
|
|
|
}
|
2013-03-11 08:44:53 +00:00
|
|
|
|
2017-06-15 03:28:25 +00:00
|
|
|
#ifdef CONFIG_SATA
|
2013-03-11 08:44:53 +00:00
|
|
|
setup_sata();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int checkboard(void)
|
|
|
|
{
|
2019-07-29 19:15:56 +00:00
|
|
|
int ret = gpio_get_value(WL12XX_WL_IRQ_GP);
|
|
|
|
|
|
|
|
if (ret < 0) {
|
|
|
|
/* The gpios have not been probed yet. Read it myself */
|
|
|
|
struct gpio_regs *regs = (struct gpio_regs *)GPIO6_BASE_ADDR;
|
|
|
|
int gpio = WL12XX_WL_IRQ_GP & 0x1f;
|
|
|
|
|
|
|
|
ret = (readl(®s->gpio_psr) >> gpio) & 0x01;
|
|
|
|
}
|
|
|
|
if (ret)
|
2013-03-11 08:44:53 +00:00
|
|
|
puts("Board: Nitrogen6X\n");
|
|
|
|
else
|
|
|
|
puts("Board: SABRE Lite\n");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct button_key {
|
|
|
|
char const *name;
|
|
|
|
unsigned gpnum;
|
|
|
|
char ident;
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct button_key const buttons[] = {
|
|
|
|
{"back", IMX_GPIO_NR(2, 2), 'B'},
|
|
|
|
{"home", IMX_GPIO_NR(2, 4), 'H'},
|
|
|
|
{"menu", IMX_GPIO_NR(2, 1), 'M'},
|
|
|
|
{"search", IMX_GPIO_NR(2, 3), 'S'},
|
|
|
|
{"volup", IMX_GPIO_NR(7, 13), 'V'},
|
|
|
|
{"voldown", IMX_GPIO_NR(4, 5), 'v'},
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* generate a null-terminated string containing the buttons pressed
|
|
|
|
* returns number of keys pressed
|
|
|
|
*/
|
|
|
|
static int read_keys(char *buf)
|
|
|
|
{
|
|
|
|
int i, numpressed = 0;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(buttons); i++) {
|
|
|
|
if (!gpio_get_value(buttons[i].gpnum))
|
|
|
|
buf[numpressed++] = buttons[i].ident;
|
|
|
|
}
|
|
|
|
buf[numpressed] = '\0';
|
|
|
|
return numpressed;
|
|
|
|
}
|
|
|
|
|
2020-05-10 17:40:03 +00:00
|
|
|
static int do_kbd(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
|
2013-03-11 08:44:53 +00:00
|
|
|
{
|
|
|
|
char envvalue[ARRAY_SIZE(buttons)+1];
|
|
|
|
int numpressed = read_keys(envvalue);
|
2017-08-03 18:22:09 +00:00
|
|
|
env_set("keybd", envvalue);
|
2013-03-11 08:44:53 +00:00
|
|
|
return numpressed == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
U_BOOT_CMD(
|
|
|
|
kbd, 1, 1, do_kbd,
|
|
|
|
"Tests for keypresses, sets 'keybd' environment variable",
|
|
|
|
"Returns 0 (true) to shell if key is pressed."
|
|
|
|
);
|
|
|
|
|
|
|
|
#ifdef CONFIG_PREBOOT
|
|
|
|
static char const kbd_magic_prefix[] = "key_magic";
|
|
|
|
static char const kbd_command_prefix[] = "key_cmd";
|
|
|
|
|
|
|
|
static void preboot_keys(void)
|
|
|
|
{
|
|
|
|
int numpressed;
|
|
|
|
char keypress[ARRAY_SIZE(buttons)+1];
|
|
|
|
numpressed = read_keys(keypress);
|
|
|
|
if (numpressed) {
|
2017-08-03 18:22:12 +00:00
|
|
|
char *kbd_magic_keys = env_get("magic_keys");
|
2013-03-11 08:44:53 +00:00
|
|
|
char *suffix;
|
|
|
|
/*
|
|
|
|
* loop over all magic keys
|
|
|
|
*/
|
|
|
|
for (suffix = kbd_magic_keys; *suffix; ++suffix) {
|
|
|
|
char *keys;
|
|
|
|
char magic[sizeof(kbd_magic_prefix) + 1];
|
|
|
|
sprintf(magic, "%s%c", kbd_magic_prefix, *suffix);
|
2017-08-03 18:22:12 +00:00
|
|
|
keys = env_get(magic);
|
2013-03-11 08:44:53 +00:00
|
|
|
if (keys) {
|
|
|
|
if (!strcmp(keys, keypress))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (*suffix) {
|
|
|
|
char cmd_name[sizeof(kbd_command_prefix) + 1];
|
|
|
|
char *cmd;
|
|
|
|
sprintf(cmd_name, "%s%c", kbd_command_prefix, *suffix);
|
2017-08-03 18:22:12 +00:00
|
|
|
cmd = env_get(cmd_name);
|
2013-03-11 08:44:53 +00:00
|
|
|
if (cmd) {
|
2017-08-03 18:22:09 +00:00
|
|
|
env_set("preboot", cmd);
|
2013-03-11 08:44:53 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef CONFIG_CMD_BMODE
|
|
|
|
static const struct boot_mode board_boot_modes[] = {
|
|
|
|
/* 4 bit bus width */
|
|
|
|
{"mmc0", MAKE_CFGVAL(0x40, 0x30, 0x00, 0x00)},
|
|
|
|
{"mmc1", MAKE_CFGVAL(0x40, 0x38, 0x00, 0x00)},
|
|
|
|
{NULL, 0},
|
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
|
|
|
int misc_init_r(void)
|
|
|
|
{
|
2019-07-29 19:15:56 +00:00
|
|
|
gpio_request(RGB_BACKLIGHT_GP, "lvds backlight");
|
|
|
|
gpio_request(LVDS_BACKLIGHT_GP, "lvds backlight");
|
|
|
|
gpio_request(GP_USB_OTG_PWR, "usbotg power");
|
|
|
|
gpio_request(IMX_GPIO_NR(7, 12), "usbh1 hub reset");
|
|
|
|
gpio_request(IMX_GPIO_NR(2, 2), "back");
|
|
|
|
gpio_request(IMX_GPIO_NR(2, 4), "home");
|
|
|
|
gpio_request(IMX_GPIO_NR(2, 1), "menu");
|
|
|
|
gpio_request(IMX_GPIO_NR(2, 3), "search");
|
|
|
|
gpio_request(IMX_GPIO_NR(7, 13), "volup");
|
|
|
|
gpio_request(IMX_GPIO_NR(4, 5), "voldown");
|
2013-03-11 08:44:53 +00:00
|
|
|
#ifdef CONFIG_PREBOOT
|
|
|
|
preboot_keys();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef CONFIG_CMD_BMODE
|
|
|
|
add_board_boot_modes(board_boot_modes);
|
|
|
|
#endif
|
2017-08-03 18:22:10 +00:00
|
|
|
env_set_hex("reset_cause", get_imx_reset_cause());
|
2013-03-11 08:44:53 +00:00
|
|
|
return 0;
|
|
|
|
}
|