1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright (C) 2015 Freescale Semiconductor, Inc.
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Author: Fabio Estevam <fabio.estevam@freescale.com>
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * Copyright (C) 2013 Jon Nettleton <jon.nettleton@gmail.com>
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun * Based on SPL code from Solidrun tree, which is:
9*4882a593Smuzhiyun * Author: Tungyi Lin <tungyilin1127@gmail.com>
10*4882a593Smuzhiyun *
11*4882a593Smuzhiyun * Derived from EDM_CF_IMX6 code by TechNexion,Inc
12*4882a593Smuzhiyun * Ported to SolidRun microSOM by Rabeeh Khoury <rabeeh@solid-run.com>
13*4882a593Smuzhiyun *
14*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0+
15*4882a593Smuzhiyun */
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun #include <asm/arch/clock.h>
18*4882a593Smuzhiyun #include <asm/arch/imx-regs.h>
19*4882a593Smuzhiyun #include <asm/arch/iomux.h>
20*4882a593Smuzhiyun #include <asm/arch/mx6-pins.h>
21*4882a593Smuzhiyun #include <asm/arch/mxc_hdmi.h>
22*4882a593Smuzhiyun #include <linux/errno.h>
23*4882a593Smuzhiyun #include <asm/gpio.h>
24*4882a593Smuzhiyun #include <asm/mach-imx/iomux-v3.h>
25*4882a593Smuzhiyun #include <asm/mach-imx/sata.h>
26*4882a593Smuzhiyun #include <asm/mach-imx/video.h>
27*4882a593Smuzhiyun #include <mmc.h>
28*4882a593Smuzhiyun #include <fsl_esdhc.h>
29*4882a593Smuzhiyun #include <malloc.h>
30*4882a593Smuzhiyun #include <miiphy.h>
31*4882a593Smuzhiyun #include <netdev.h>
32*4882a593Smuzhiyun #include <asm/arch/crm_regs.h>
33*4882a593Smuzhiyun #include <asm/io.h>
34*4882a593Smuzhiyun #include <asm/arch/sys_proto.h>
35*4882a593Smuzhiyun #include <spl.h>
36*4882a593Smuzhiyun #include <usb.h>
37*4882a593Smuzhiyun #include <usb/ehci-ci.h>
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun DECLARE_GLOBAL_DATA_PTR;
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun #define UART_PAD_CTRL (PAD_CTL_PUS_100K_UP | \
42*4882a593Smuzhiyun PAD_CTL_SPEED_MED | PAD_CTL_DSE_40ohm | \
43*4882a593Smuzhiyun PAD_CTL_SRE_FAST | PAD_CTL_HYS)
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun #define USDHC_PAD_CTRL (PAD_CTL_PUS_47K_UP | \
46*4882a593Smuzhiyun PAD_CTL_SPEED_LOW | PAD_CTL_DSE_80ohm | \
47*4882a593Smuzhiyun PAD_CTL_SRE_FAST | PAD_CTL_HYS)
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun #define ENET_PAD_CTRL (PAD_CTL_PUS_100K_UP | \
50*4882a593Smuzhiyun PAD_CTL_SPEED_MED | PAD_CTL_DSE_40ohm | PAD_CTL_HYS)
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun #define ENET_PAD_CTRL_PD (PAD_CTL_PUS_100K_DOWN | \
53*4882a593Smuzhiyun PAD_CTL_SPEED_MED | PAD_CTL_DSE_40ohm | PAD_CTL_HYS)
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun #define ENET_PAD_CTRL_CLK ((PAD_CTL_PUS_100K_UP & ~PAD_CTL_PKE) | \
56*4882a593Smuzhiyun PAD_CTL_SPEED_MED | PAD_CTL_DSE_40ohm | PAD_CTL_SRE_FAST)
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun #define ETH_PHY_RESET IMX_GPIO_NR(4, 15)
59*4882a593Smuzhiyun #define USB_H1_VBUS IMX_GPIO_NR(1, 0)
60*4882a593Smuzhiyun
dram_init(void)61*4882a593Smuzhiyun int dram_init(void)
62*4882a593Smuzhiyun {
63*4882a593Smuzhiyun gd->ram_size = imx_ddr_size();
64*4882a593Smuzhiyun return 0;
65*4882a593Smuzhiyun }
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun static iomux_v3_cfg_t const uart1_pads[] = {
68*4882a593Smuzhiyun IOMUX_PADS(PAD_CSI0_DAT10__UART1_TX_DATA | MUX_PAD_CTRL(UART_PAD_CTRL)),
69*4882a593Smuzhiyun IOMUX_PADS(PAD_CSI0_DAT11__UART1_RX_DATA | MUX_PAD_CTRL(UART_PAD_CTRL)),
70*4882a593Smuzhiyun };
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun static iomux_v3_cfg_t const usdhc2_pads[] = {
73*4882a593Smuzhiyun IOMUX_PADS(PAD_SD2_CLK__SD2_CLK | MUX_PAD_CTRL(USDHC_PAD_CTRL)),
74*4882a593Smuzhiyun IOMUX_PADS(PAD_SD2_CMD__SD2_CMD | MUX_PAD_CTRL(USDHC_PAD_CTRL)),
75*4882a593Smuzhiyun IOMUX_PADS(PAD_SD2_DAT0__SD2_DATA0 | MUX_PAD_CTRL(USDHC_PAD_CTRL)),
76*4882a593Smuzhiyun IOMUX_PADS(PAD_SD2_DAT1__SD2_DATA1 | MUX_PAD_CTRL(USDHC_PAD_CTRL)),
77*4882a593Smuzhiyun IOMUX_PADS(PAD_SD2_DAT2__SD2_DATA2 | MUX_PAD_CTRL(USDHC_PAD_CTRL)),
78*4882a593Smuzhiyun IOMUX_PADS(PAD_SD2_DAT3__SD2_DATA3 | MUX_PAD_CTRL(USDHC_PAD_CTRL)),
79*4882a593Smuzhiyun };
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun static iomux_v3_cfg_t const hb_cbi_sense[] = {
82*4882a593Smuzhiyun /* These pins are for sensing if it is a CuBox-i or a HummingBoard */
83*4882a593Smuzhiyun IOMUX_PADS(PAD_KEY_ROW1__GPIO4_IO09 | MUX_PAD_CTRL(UART_PAD_CTRL)),
84*4882a593Smuzhiyun IOMUX_PADS(PAD_EIM_DA4__GPIO3_IO04 | MUX_PAD_CTRL(UART_PAD_CTRL)),
85*4882a593Smuzhiyun };
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun static iomux_v3_cfg_t const usb_pads[] = {
88*4882a593Smuzhiyun IOMUX_PADS(PAD_GPIO_0__GPIO1_IO00 | MUX_PAD_CTRL(NO_PAD_CTRL)),
89*4882a593Smuzhiyun };
90*4882a593Smuzhiyun
setup_iomux_uart(void)91*4882a593Smuzhiyun static void setup_iomux_uart(void)
92*4882a593Smuzhiyun {
93*4882a593Smuzhiyun SETUP_IOMUX_PADS(uart1_pads);
94*4882a593Smuzhiyun }
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun static struct fsl_esdhc_cfg usdhc_cfg[1] = {
97*4882a593Smuzhiyun {USDHC2_BASE_ADDR},
98*4882a593Smuzhiyun };
99*4882a593Smuzhiyun
board_mmc_getcd(struct mmc * mmc)100*4882a593Smuzhiyun int board_mmc_getcd(struct mmc *mmc)
101*4882a593Smuzhiyun {
102*4882a593Smuzhiyun return 1; /* uSDHC2 is always present */
103*4882a593Smuzhiyun }
104*4882a593Smuzhiyun
board_mmc_init(bd_t * bis)105*4882a593Smuzhiyun int board_mmc_init(bd_t *bis)
106*4882a593Smuzhiyun {
107*4882a593Smuzhiyun SETUP_IOMUX_PADS(usdhc2_pads);
108*4882a593Smuzhiyun usdhc_cfg[0].esdhc_base = USDHC2_BASE_ADDR;
109*4882a593Smuzhiyun usdhc_cfg[0].sdhc_clk = mxc_get_clock(MXC_ESDHC2_CLK);
110*4882a593Smuzhiyun gd->arch.sdhc_clk = usdhc_cfg[0].sdhc_clk;
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun return fsl_esdhc_initialize(bis, &usdhc_cfg[0]);
113*4882a593Smuzhiyun }
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun static iomux_v3_cfg_t const enet_pads[] = {
116*4882a593Smuzhiyun IOMUX_PADS(PAD_ENET_MDIO__ENET_MDIO | MUX_PAD_CTRL(ENET_PAD_CTRL)),
117*4882a593Smuzhiyun IOMUX_PADS(PAD_ENET_MDC__ENET_MDC | MUX_PAD_CTRL(ENET_PAD_CTRL)),
118*4882a593Smuzhiyun /* AR8035 reset */
119*4882a593Smuzhiyun IOMUX_PADS(PAD_KEY_ROW4__GPIO4_IO15 | MUX_PAD_CTRL(ENET_PAD_CTRL_PD)),
120*4882a593Smuzhiyun /* AR8035 interrupt */
121*4882a593Smuzhiyun IOMUX_PADS(PAD_DI0_PIN2__GPIO4_IO18 | MUX_PAD_CTRL(NO_PAD_CTRL)),
122*4882a593Smuzhiyun /* GPIO16 -> AR8035 25MHz */
123*4882a593Smuzhiyun IOMUX_PADS(PAD_GPIO_16__ENET_REF_CLK | MUX_PAD_CTRL(NO_PAD_CTRL)),
124*4882a593Smuzhiyun IOMUX_PADS(PAD_RGMII_TXC__RGMII_TXC | MUX_PAD_CTRL(NO_PAD_CTRL)),
125*4882a593Smuzhiyun IOMUX_PADS(PAD_RGMII_TD0__RGMII_TD0 | MUX_PAD_CTRL(ENET_PAD_CTRL)),
126*4882a593Smuzhiyun IOMUX_PADS(PAD_RGMII_TD1__RGMII_TD1 | MUX_PAD_CTRL(ENET_PAD_CTRL)),
127*4882a593Smuzhiyun IOMUX_PADS(PAD_RGMII_TD2__RGMII_TD2 | MUX_PAD_CTRL(ENET_PAD_CTRL)),
128*4882a593Smuzhiyun IOMUX_PADS(PAD_RGMII_TD3__RGMII_TD3 | MUX_PAD_CTRL(ENET_PAD_CTRL)),
129*4882a593Smuzhiyun IOMUX_PADS(PAD_RGMII_TX_CTL__RGMII_TX_CTL | MUX_PAD_CTRL(ENET_PAD_CTRL)),
130*4882a593Smuzhiyun /* AR8035 CLK_25M --> ENET_REF_CLK (V22) */
131*4882a593Smuzhiyun IOMUX_PADS(PAD_ENET_REF_CLK__ENET_TX_CLK | MUX_PAD_CTRL(ENET_PAD_CTRL_CLK)),
132*4882a593Smuzhiyun IOMUX_PADS(PAD_RGMII_RXC__RGMII_RXC | MUX_PAD_CTRL(ENET_PAD_CTRL)),
133*4882a593Smuzhiyun IOMUX_PADS(PAD_RGMII_RD0__RGMII_RD0 | MUX_PAD_CTRL(ENET_PAD_CTRL_PD)),
134*4882a593Smuzhiyun IOMUX_PADS(PAD_RGMII_RD1__RGMII_RD1 | MUX_PAD_CTRL(ENET_PAD_CTRL_PD)),
135*4882a593Smuzhiyun IOMUX_PADS(PAD_RGMII_RD2__RGMII_RD2 | MUX_PAD_CTRL(ENET_PAD_CTRL)),
136*4882a593Smuzhiyun IOMUX_PADS(PAD_RGMII_RD3__RGMII_RD3 | MUX_PAD_CTRL(ENET_PAD_CTRL)),
137*4882a593Smuzhiyun IOMUX_PADS(PAD_RGMII_RX_CTL__RGMII_RX_CTL | MUX_PAD_CTRL(ENET_PAD_CTRL_PD)),
138*4882a593Smuzhiyun IOMUX_PADS(PAD_ENET_RXD0__GPIO1_IO27 | MUX_PAD_CTRL(ENET_PAD_CTRL_PD)),
139*4882a593Smuzhiyun IOMUX_PADS(PAD_ENET_RXD1__GPIO1_IO26 | MUX_PAD_CTRL(ENET_PAD_CTRL_PD)),
140*4882a593Smuzhiyun };
141*4882a593Smuzhiyun
setup_iomux_enet(void)142*4882a593Smuzhiyun static void setup_iomux_enet(void)
143*4882a593Smuzhiyun {
144*4882a593Smuzhiyun SETUP_IOMUX_PADS(enet_pads);
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun gpio_direction_output(ETH_PHY_RESET, 0);
147*4882a593Smuzhiyun mdelay(10);
148*4882a593Smuzhiyun gpio_set_value(ETH_PHY_RESET, 1);
149*4882a593Smuzhiyun udelay(100);
150*4882a593Smuzhiyun }
151*4882a593Smuzhiyun
board_phy_config(struct phy_device * phydev)152*4882a593Smuzhiyun int board_phy_config(struct phy_device *phydev)
153*4882a593Smuzhiyun {
154*4882a593Smuzhiyun if (phydev->drv->config)
155*4882a593Smuzhiyun phydev->drv->config(phydev);
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun return 0;
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun /* On Cuboxi Ethernet PHY can be located at addresses 0x0 or 0x4 */
161*4882a593Smuzhiyun #define ETH_PHY_MASK ((1 << 0x0) | (1 << 0x4))
162*4882a593Smuzhiyun
board_eth_init(bd_t * bis)163*4882a593Smuzhiyun int board_eth_init(bd_t *bis)
164*4882a593Smuzhiyun {
165*4882a593Smuzhiyun struct iomuxc *const iomuxc_regs = (struct iomuxc *)IOMUXC_BASE_ADDR;
166*4882a593Smuzhiyun struct mii_dev *bus;
167*4882a593Smuzhiyun struct phy_device *phydev;
168*4882a593Smuzhiyun
169*4882a593Smuzhiyun int ret = enable_fec_anatop_clock(0, ENET_25MHZ);
170*4882a593Smuzhiyun if (ret)
171*4882a593Smuzhiyun return ret;
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun /* set gpr1[ENET_CLK_SEL] */
174*4882a593Smuzhiyun setbits_le32(&iomuxc_regs->gpr[1], IOMUXC_GPR1_ENET_CLK_SEL_MASK);
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun setup_iomux_enet();
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun bus = fec_get_miibus(IMX_FEC_BASE, -1);
179*4882a593Smuzhiyun if (!bus)
180*4882a593Smuzhiyun return -EINVAL;
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun phydev = phy_find_by_mask(bus, ETH_PHY_MASK, PHY_INTERFACE_MODE_RGMII);
183*4882a593Smuzhiyun if (!phydev) {
184*4882a593Smuzhiyun ret = -EINVAL;
185*4882a593Smuzhiyun goto free_bus;
186*4882a593Smuzhiyun }
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun debug("using phy at address %d\n", phydev->addr);
189*4882a593Smuzhiyun ret = fec_probe(bis, -1, IMX_FEC_BASE, bus, phydev);
190*4882a593Smuzhiyun if (ret)
191*4882a593Smuzhiyun goto free_phydev;
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun return 0;
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun free_phydev:
196*4882a593Smuzhiyun free(phydev);
197*4882a593Smuzhiyun free_bus:
198*4882a593Smuzhiyun free(bus);
199*4882a593Smuzhiyun return ret;
200*4882a593Smuzhiyun }
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun #ifdef CONFIG_VIDEO_IPUV3
do_enable_hdmi(struct display_info_t const * dev)203*4882a593Smuzhiyun static void do_enable_hdmi(struct display_info_t const *dev)
204*4882a593Smuzhiyun {
205*4882a593Smuzhiyun imx_enable_hdmi_phy();
206*4882a593Smuzhiyun }
207*4882a593Smuzhiyun
208*4882a593Smuzhiyun struct display_info_t const displays[] = {
209*4882a593Smuzhiyun {
210*4882a593Smuzhiyun .bus = -1,
211*4882a593Smuzhiyun .addr = 0,
212*4882a593Smuzhiyun .pixfmt = IPU_PIX_FMT_RGB24,
213*4882a593Smuzhiyun .detect = detect_hdmi,
214*4882a593Smuzhiyun .enable = do_enable_hdmi,
215*4882a593Smuzhiyun .mode = {
216*4882a593Smuzhiyun .name = "HDMI",
217*4882a593Smuzhiyun /* 1024x768@60Hz (VESA)*/
218*4882a593Smuzhiyun .refresh = 60,
219*4882a593Smuzhiyun .xres = 1024,
220*4882a593Smuzhiyun .yres = 768,
221*4882a593Smuzhiyun .pixclock = 15384,
222*4882a593Smuzhiyun .left_margin = 160,
223*4882a593Smuzhiyun .right_margin = 24,
224*4882a593Smuzhiyun .upper_margin = 29,
225*4882a593Smuzhiyun .lower_margin = 3,
226*4882a593Smuzhiyun .hsync_len = 136,
227*4882a593Smuzhiyun .vsync_len = 6,
228*4882a593Smuzhiyun .sync = FB_SYNC_EXT,
229*4882a593Smuzhiyun .vmode = FB_VMODE_NONINTERLACED
230*4882a593Smuzhiyun }
231*4882a593Smuzhiyun }
232*4882a593Smuzhiyun };
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun size_t display_count = ARRAY_SIZE(displays);
235*4882a593Smuzhiyun
setup_display(void)236*4882a593Smuzhiyun static int setup_display(void)
237*4882a593Smuzhiyun {
238*4882a593Smuzhiyun struct mxc_ccm_reg *ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
239*4882a593Smuzhiyun int reg;
240*4882a593Smuzhiyun int timeout = 100000;
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun enable_ipu_clock();
243*4882a593Smuzhiyun imx_setup_hdmi();
244*4882a593Smuzhiyun
245*4882a593Smuzhiyun /* set video pll to 455MHz (24MHz * (37+11/12) / 2) */
246*4882a593Smuzhiyun setbits_le32(&ccm->analog_pll_video, BM_ANADIG_PLL_VIDEO_POWERDOWN);
247*4882a593Smuzhiyun
248*4882a593Smuzhiyun reg = readl(&ccm->analog_pll_video);
249*4882a593Smuzhiyun reg &= ~BM_ANADIG_PLL_VIDEO_DIV_SELECT;
250*4882a593Smuzhiyun reg |= BF_ANADIG_PLL_VIDEO_DIV_SELECT(37);
251*4882a593Smuzhiyun reg &= ~BM_ANADIG_PLL_VIDEO_POST_DIV_SELECT;
252*4882a593Smuzhiyun reg |= BF_ANADIG_PLL_VIDEO_POST_DIV_SELECT(1);
253*4882a593Smuzhiyun writel(reg, &ccm->analog_pll_video);
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun writel(BF_ANADIG_PLL_VIDEO_NUM_A(11), &ccm->analog_pll_video_num);
256*4882a593Smuzhiyun writel(BF_ANADIG_PLL_VIDEO_DENOM_B(12), &ccm->analog_pll_video_denom);
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun reg &= ~BM_ANADIG_PLL_VIDEO_POWERDOWN;
259*4882a593Smuzhiyun writel(reg, &ccm->analog_pll_video);
260*4882a593Smuzhiyun
261*4882a593Smuzhiyun while (timeout--)
262*4882a593Smuzhiyun if (readl(&ccm->analog_pll_video) & BM_ANADIG_PLL_VIDEO_LOCK)
263*4882a593Smuzhiyun break;
264*4882a593Smuzhiyun if (timeout < 0) {
265*4882a593Smuzhiyun printf("Warning: video pll lock timeout!\n");
266*4882a593Smuzhiyun return -ETIMEDOUT;
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun
269*4882a593Smuzhiyun reg = readl(&ccm->analog_pll_video);
270*4882a593Smuzhiyun reg |= BM_ANADIG_PLL_VIDEO_ENABLE;
271*4882a593Smuzhiyun reg &= ~BM_ANADIG_PLL_VIDEO_BYPASS;
272*4882a593Smuzhiyun writel(reg, &ccm->analog_pll_video);
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun /* gate ipu1_di0_clk */
275*4882a593Smuzhiyun clrbits_le32(&ccm->CCGR3, MXC_CCM_CCGR3_LDB_DI0_MASK);
276*4882a593Smuzhiyun
277*4882a593Smuzhiyun /* select video_pll clock / 7 for ipu1_di0_clk -> 65MHz pixclock */
278*4882a593Smuzhiyun reg = readl(&ccm->chsccdr);
279*4882a593Smuzhiyun reg &= ~(MXC_CCM_CHSCCDR_IPU1_DI0_PRE_CLK_SEL_MASK |
280*4882a593Smuzhiyun MXC_CCM_CHSCCDR_IPU1_DI0_PODF_MASK |
281*4882a593Smuzhiyun MXC_CCM_CHSCCDR_IPU1_DI0_CLK_SEL_MASK);
282*4882a593Smuzhiyun reg |= (2 << MXC_CCM_CHSCCDR_IPU1_DI0_PRE_CLK_SEL_OFFSET) |
283*4882a593Smuzhiyun (6 << MXC_CCM_CHSCCDR_IPU1_DI0_PODF_OFFSET) |
284*4882a593Smuzhiyun (0 << MXC_CCM_CHSCCDR_IPU1_DI0_CLK_SEL_OFFSET);
285*4882a593Smuzhiyun writel(reg, &ccm->chsccdr);
286*4882a593Smuzhiyun
287*4882a593Smuzhiyun /* enable ipu1_di0_clk */
288*4882a593Smuzhiyun setbits_le32(&ccm->CCGR3, MXC_CCM_CCGR3_LDB_DI0_MASK);
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun return 0;
291*4882a593Smuzhiyun }
292*4882a593Smuzhiyun #endif /* CONFIG_VIDEO_IPUV3 */
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun #ifdef CONFIG_USB_EHCI_MX6
setup_usb(void)295*4882a593Smuzhiyun static void setup_usb(void)
296*4882a593Smuzhiyun {
297*4882a593Smuzhiyun SETUP_IOMUX_PADS(usb_pads);
298*4882a593Smuzhiyun }
299*4882a593Smuzhiyun
board_ehci_hcd_init(int port)300*4882a593Smuzhiyun int board_ehci_hcd_init(int port)
301*4882a593Smuzhiyun {
302*4882a593Smuzhiyun if (port == 1)
303*4882a593Smuzhiyun gpio_direction_output(USB_H1_VBUS, 1);
304*4882a593Smuzhiyun
305*4882a593Smuzhiyun return 0;
306*4882a593Smuzhiyun }
307*4882a593Smuzhiyun #endif
308*4882a593Smuzhiyun
board_early_init_f(void)309*4882a593Smuzhiyun int board_early_init_f(void)
310*4882a593Smuzhiyun {
311*4882a593Smuzhiyun int ret = 0;
312*4882a593Smuzhiyun setup_iomux_uart();
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun #ifdef CONFIG_VIDEO_IPUV3
315*4882a593Smuzhiyun ret = setup_display();
316*4882a593Smuzhiyun #endif
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun #ifdef CONFIG_CMD_SATA
319*4882a593Smuzhiyun setup_sata();
320*4882a593Smuzhiyun #endif
321*4882a593Smuzhiyun
322*4882a593Smuzhiyun #ifdef CONFIG_USB_EHCI_MX6
323*4882a593Smuzhiyun setup_usb();
324*4882a593Smuzhiyun #endif
325*4882a593Smuzhiyun return ret;
326*4882a593Smuzhiyun }
327*4882a593Smuzhiyun
board_init(void)328*4882a593Smuzhiyun int board_init(void)
329*4882a593Smuzhiyun {
330*4882a593Smuzhiyun /* address of boot parameters */
331*4882a593Smuzhiyun gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100;
332*4882a593Smuzhiyun
333*4882a593Smuzhiyun return 0;
334*4882a593Smuzhiyun }
335*4882a593Smuzhiyun
is_hummingboard(void)336*4882a593Smuzhiyun static bool is_hummingboard(void)
337*4882a593Smuzhiyun {
338*4882a593Smuzhiyun int val1, val2;
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun SETUP_IOMUX_PADS(hb_cbi_sense);
341*4882a593Smuzhiyun
342*4882a593Smuzhiyun gpio_direction_input(IMX_GPIO_NR(4, 9));
343*4882a593Smuzhiyun gpio_direction_input(IMX_GPIO_NR(3, 4));
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun val1 = gpio_get_value(IMX_GPIO_NR(4, 9));
346*4882a593Smuzhiyun val2 = gpio_get_value(IMX_GPIO_NR(3, 4));
347*4882a593Smuzhiyun
348*4882a593Smuzhiyun /*
349*4882a593Smuzhiyun * Machine selection -
350*4882a593Smuzhiyun * Machine val1, val2
351*4882a593Smuzhiyun * -------------------------
352*4882a593Smuzhiyun * HB rev 3.x x 0
353*4882a593Smuzhiyun * CBi 0 1
354*4882a593Smuzhiyun * HB 1 1
355*4882a593Smuzhiyun */
356*4882a593Smuzhiyun
357*4882a593Smuzhiyun if (val2 == 0)
358*4882a593Smuzhiyun return true;
359*4882a593Smuzhiyun else if (val1 == 0)
360*4882a593Smuzhiyun return false;
361*4882a593Smuzhiyun else
362*4882a593Smuzhiyun return true;
363*4882a593Smuzhiyun }
364*4882a593Smuzhiyun
checkboard(void)365*4882a593Smuzhiyun int checkboard(void)
366*4882a593Smuzhiyun {
367*4882a593Smuzhiyun if (is_hummingboard())
368*4882a593Smuzhiyun puts("Board: MX6 Hummingboard\n");
369*4882a593Smuzhiyun else
370*4882a593Smuzhiyun puts("Board: MX6 Cubox-i\n");
371*4882a593Smuzhiyun
372*4882a593Smuzhiyun return 0;
373*4882a593Smuzhiyun }
374*4882a593Smuzhiyun
board_late_init(void)375*4882a593Smuzhiyun int board_late_init(void)
376*4882a593Smuzhiyun {
377*4882a593Smuzhiyun #ifdef CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG
378*4882a593Smuzhiyun if (is_hummingboard())
379*4882a593Smuzhiyun env_set("board_name", "HUMMINGBOARD");
380*4882a593Smuzhiyun else
381*4882a593Smuzhiyun env_set("board_name", "CUBOXI");
382*4882a593Smuzhiyun
383*4882a593Smuzhiyun if (is_mx6dq())
384*4882a593Smuzhiyun env_set("board_rev", "MX6Q");
385*4882a593Smuzhiyun else
386*4882a593Smuzhiyun env_set("board_rev", "MX6DL");
387*4882a593Smuzhiyun #endif
388*4882a593Smuzhiyun
389*4882a593Smuzhiyun return 0;
390*4882a593Smuzhiyun }
391*4882a593Smuzhiyun
392*4882a593Smuzhiyun #ifdef CONFIG_SPL_BUILD
393*4882a593Smuzhiyun #include <asm/arch/mx6-ddr.h>
394*4882a593Smuzhiyun static const struct mx6dq_iomux_ddr_regs mx6q_ddr_ioregs = {
395*4882a593Smuzhiyun .dram_sdclk_0 = 0x00020030,
396*4882a593Smuzhiyun .dram_sdclk_1 = 0x00020030,
397*4882a593Smuzhiyun .dram_cas = 0x00020030,
398*4882a593Smuzhiyun .dram_ras = 0x00020030,
399*4882a593Smuzhiyun .dram_reset = 0x00020030,
400*4882a593Smuzhiyun .dram_sdcke0 = 0x00003000,
401*4882a593Smuzhiyun .dram_sdcke1 = 0x00003000,
402*4882a593Smuzhiyun .dram_sdba2 = 0x00000000,
403*4882a593Smuzhiyun .dram_sdodt0 = 0x00003030,
404*4882a593Smuzhiyun .dram_sdodt1 = 0x00003030,
405*4882a593Smuzhiyun .dram_sdqs0 = 0x00000030,
406*4882a593Smuzhiyun .dram_sdqs1 = 0x00000030,
407*4882a593Smuzhiyun .dram_sdqs2 = 0x00000030,
408*4882a593Smuzhiyun .dram_sdqs3 = 0x00000030,
409*4882a593Smuzhiyun .dram_sdqs4 = 0x00000030,
410*4882a593Smuzhiyun .dram_sdqs5 = 0x00000030,
411*4882a593Smuzhiyun .dram_sdqs6 = 0x00000030,
412*4882a593Smuzhiyun .dram_sdqs7 = 0x00000030,
413*4882a593Smuzhiyun .dram_dqm0 = 0x00020030,
414*4882a593Smuzhiyun .dram_dqm1 = 0x00020030,
415*4882a593Smuzhiyun .dram_dqm2 = 0x00020030,
416*4882a593Smuzhiyun .dram_dqm3 = 0x00020030,
417*4882a593Smuzhiyun .dram_dqm4 = 0x00020030,
418*4882a593Smuzhiyun .dram_dqm5 = 0x00020030,
419*4882a593Smuzhiyun .dram_dqm6 = 0x00020030,
420*4882a593Smuzhiyun .dram_dqm7 = 0x00020030,
421*4882a593Smuzhiyun };
422*4882a593Smuzhiyun
423*4882a593Smuzhiyun static const struct mx6sdl_iomux_ddr_regs mx6dl_ddr_ioregs = {
424*4882a593Smuzhiyun .dram_sdclk_0 = 0x00000028,
425*4882a593Smuzhiyun .dram_sdclk_1 = 0x00000028,
426*4882a593Smuzhiyun .dram_cas = 0x00000028,
427*4882a593Smuzhiyun .dram_ras = 0x00000028,
428*4882a593Smuzhiyun .dram_reset = 0x000c0028,
429*4882a593Smuzhiyun .dram_sdcke0 = 0x00003000,
430*4882a593Smuzhiyun .dram_sdcke1 = 0x00003000,
431*4882a593Smuzhiyun .dram_sdba2 = 0x00000000,
432*4882a593Smuzhiyun .dram_sdodt0 = 0x00003030,
433*4882a593Smuzhiyun .dram_sdodt1 = 0x00003030,
434*4882a593Smuzhiyun .dram_sdqs0 = 0x00000028,
435*4882a593Smuzhiyun .dram_sdqs1 = 0x00000028,
436*4882a593Smuzhiyun .dram_sdqs2 = 0x00000028,
437*4882a593Smuzhiyun .dram_sdqs3 = 0x00000028,
438*4882a593Smuzhiyun .dram_sdqs4 = 0x00000028,
439*4882a593Smuzhiyun .dram_sdqs5 = 0x00000028,
440*4882a593Smuzhiyun .dram_sdqs6 = 0x00000028,
441*4882a593Smuzhiyun .dram_sdqs7 = 0x00000028,
442*4882a593Smuzhiyun .dram_dqm0 = 0x00000028,
443*4882a593Smuzhiyun .dram_dqm1 = 0x00000028,
444*4882a593Smuzhiyun .dram_dqm2 = 0x00000028,
445*4882a593Smuzhiyun .dram_dqm3 = 0x00000028,
446*4882a593Smuzhiyun .dram_dqm4 = 0x00000028,
447*4882a593Smuzhiyun .dram_dqm5 = 0x00000028,
448*4882a593Smuzhiyun .dram_dqm6 = 0x00000028,
449*4882a593Smuzhiyun .dram_dqm7 = 0x00000028,
450*4882a593Smuzhiyun };
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun static const struct mx6dq_iomux_grp_regs mx6q_grp_ioregs = {
453*4882a593Smuzhiyun .grp_ddr_type = 0x000C0000,
454*4882a593Smuzhiyun .grp_ddrmode_ctl = 0x00020000,
455*4882a593Smuzhiyun .grp_ddrpke = 0x00000000,
456*4882a593Smuzhiyun .grp_addds = 0x00000030,
457*4882a593Smuzhiyun .grp_ctlds = 0x00000030,
458*4882a593Smuzhiyun .grp_ddrmode = 0x00020000,
459*4882a593Smuzhiyun .grp_b0ds = 0x00000030,
460*4882a593Smuzhiyun .grp_b1ds = 0x00000030,
461*4882a593Smuzhiyun .grp_b2ds = 0x00000030,
462*4882a593Smuzhiyun .grp_b3ds = 0x00000030,
463*4882a593Smuzhiyun .grp_b4ds = 0x00000030,
464*4882a593Smuzhiyun .grp_b5ds = 0x00000030,
465*4882a593Smuzhiyun .grp_b6ds = 0x00000030,
466*4882a593Smuzhiyun .grp_b7ds = 0x00000030,
467*4882a593Smuzhiyun };
468*4882a593Smuzhiyun
469*4882a593Smuzhiyun static const struct mx6sdl_iomux_grp_regs mx6sdl_grp_ioregs = {
470*4882a593Smuzhiyun .grp_ddr_type = 0x000c0000,
471*4882a593Smuzhiyun .grp_ddrmode_ctl = 0x00020000,
472*4882a593Smuzhiyun .grp_ddrpke = 0x00000000,
473*4882a593Smuzhiyun .grp_addds = 0x00000028,
474*4882a593Smuzhiyun .grp_ctlds = 0x00000028,
475*4882a593Smuzhiyun .grp_ddrmode = 0x00020000,
476*4882a593Smuzhiyun .grp_b0ds = 0x00000028,
477*4882a593Smuzhiyun .grp_b1ds = 0x00000028,
478*4882a593Smuzhiyun .grp_b2ds = 0x00000028,
479*4882a593Smuzhiyun .grp_b3ds = 0x00000028,
480*4882a593Smuzhiyun .grp_b4ds = 0x00000028,
481*4882a593Smuzhiyun .grp_b5ds = 0x00000028,
482*4882a593Smuzhiyun .grp_b6ds = 0x00000028,
483*4882a593Smuzhiyun .grp_b7ds = 0x00000028,
484*4882a593Smuzhiyun };
485*4882a593Smuzhiyun
486*4882a593Smuzhiyun /* microSOM with Dual processor and 1GB memory */
487*4882a593Smuzhiyun static const struct mx6_mmdc_calibration mx6q_1g_mmcd_calib = {
488*4882a593Smuzhiyun .p0_mpwldectrl0 = 0x00000000,
489*4882a593Smuzhiyun .p0_mpwldectrl1 = 0x00000000,
490*4882a593Smuzhiyun .p1_mpwldectrl0 = 0x00000000,
491*4882a593Smuzhiyun .p1_mpwldectrl1 = 0x00000000,
492*4882a593Smuzhiyun .p0_mpdgctrl0 = 0x0314031c,
493*4882a593Smuzhiyun .p0_mpdgctrl1 = 0x023e0304,
494*4882a593Smuzhiyun .p1_mpdgctrl0 = 0x03240330,
495*4882a593Smuzhiyun .p1_mpdgctrl1 = 0x03180260,
496*4882a593Smuzhiyun .p0_mprddlctl = 0x3630323c,
497*4882a593Smuzhiyun .p1_mprddlctl = 0x3436283a,
498*4882a593Smuzhiyun .p0_mpwrdlctl = 0x36344038,
499*4882a593Smuzhiyun .p1_mpwrdlctl = 0x422a423c,
500*4882a593Smuzhiyun };
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun /* microSOM with Quad processor and 2GB memory */
503*4882a593Smuzhiyun static const struct mx6_mmdc_calibration mx6q_2g_mmcd_calib = {
504*4882a593Smuzhiyun .p0_mpwldectrl0 = 0x00000000,
505*4882a593Smuzhiyun .p0_mpwldectrl1 = 0x00000000,
506*4882a593Smuzhiyun .p1_mpwldectrl0 = 0x00000000,
507*4882a593Smuzhiyun .p1_mpwldectrl1 = 0x00000000,
508*4882a593Smuzhiyun .p0_mpdgctrl0 = 0x0314031c,
509*4882a593Smuzhiyun .p0_mpdgctrl1 = 0x023e0304,
510*4882a593Smuzhiyun .p1_mpdgctrl0 = 0x03240330,
511*4882a593Smuzhiyun .p1_mpdgctrl1 = 0x03180260,
512*4882a593Smuzhiyun .p0_mprddlctl = 0x3630323c,
513*4882a593Smuzhiyun .p1_mprddlctl = 0x3436283a,
514*4882a593Smuzhiyun .p0_mpwrdlctl = 0x36344038,
515*4882a593Smuzhiyun .p1_mpwrdlctl = 0x422a423c,
516*4882a593Smuzhiyun };
517*4882a593Smuzhiyun
518*4882a593Smuzhiyun /* microSOM with Solo processor and 512MB memory */
519*4882a593Smuzhiyun static const struct mx6_mmdc_calibration mx6dl_512m_mmcd_calib = {
520*4882a593Smuzhiyun .p0_mpwldectrl0 = 0x0045004D,
521*4882a593Smuzhiyun .p0_mpwldectrl1 = 0x003A0047,
522*4882a593Smuzhiyun .p0_mpdgctrl0 = 0x023C0224,
523*4882a593Smuzhiyun .p0_mpdgctrl1 = 0x02000220,
524*4882a593Smuzhiyun .p0_mprddlctl = 0x44444846,
525*4882a593Smuzhiyun .p0_mpwrdlctl = 0x32343032,
526*4882a593Smuzhiyun };
527*4882a593Smuzhiyun
528*4882a593Smuzhiyun /* microSOM with Dual lite processor and 1GB memory */
529*4882a593Smuzhiyun static const struct mx6_mmdc_calibration mx6dl_1g_mmcd_calib = {
530*4882a593Smuzhiyun .p0_mpwldectrl0 = 0x0045004D,
531*4882a593Smuzhiyun .p0_mpwldectrl1 = 0x003A0047,
532*4882a593Smuzhiyun .p1_mpwldectrl0 = 0x001F001F,
533*4882a593Smuzhiyun .p1_mpwldectrl1 = 0x00210035,
534*4882a593Smuzhiyun .p0_mpdgctrl0 = 0x023C0224,
535*4882a593Smuzhiyun .p0_mpdgctrl1 = 0x02000220,
536*4882a593Smuzhiyun .p1_mpdgctrl0 = 0x02200220,
537*4882a593Smuzhiyun .p1_mpdgctrl1 = 0x02040208,
538*4882a593Smuzhiyun .p0_mprddlctl = 0x44444846,
539*4882a593Smuzhiyun .p1_mprddlctl = 0x4042463C,
540*4882a593Smuzhiyun .p0_mpwrdlctl = 0x32343032,
541*4882a593Smuzhiyun .p1_mpwrdlctl = 0x36363430,
542*4882a593Smuzhiyun };
543*4882a593Smuzhiyun
544*4882a593Smuzhiyun static struct mx6_ddr3_cfg mem_ddr_2g = {
545*4882a593Smuzhiyun .mem_speed = 1600,
546*4882a593Smuzhiyun .density = 2,
547*4882a593Smuzhiyun .width = 16,
548*4882a593Smuzhiyun .banks = 8,
549*4882a593Smuzhiyun .rowaddr = 14,
550*4882a593Smuzhiyun .coladdr = 10,
551*4882a593Smuzhiyun .pagesz = 2,
552*4882a593Smuzhiyun .trcd = 1375,
553*4882a593Smuzhiyun .trcmin = 4875,
554*4882a593Smuzhiyun .trasmin = 3500,
555*4882a593Smuzhiyun .SRT = 1,
556*4882a593Smuzhiyun };
557*4882a593Smuzhiyun
558*4882a593Smuzhiyun static struct mx6_ddr3_cfg mem_ddr_4g = {
559*4882a593Smuzhiyun .mem_speed = 1600,
560*4882a593Smuzhiyun .density = 4,
561*4882a593Smuzhiyun .width = 16,
562*4882a593Smuzhiyun .banks = 8,
563*4882a593Smuzhiyun .rowaddr = 15,
564*4882a593Smuzhiyun .coladdr = 10,
565*4882a593Smuzhiyun .pagesz = 2,
566*4882a593Smuzhiyun .trcd = 1375,
567*4882a593Smuzhiyun .trcmin = 4875,
568*4882a593Smuzhiyun .trasmin = 3500,
569*4882a593Smuzhiyun };
570*4882a593Smuzhiyun
ccgr_init(void)571*4882a593Smuzhiyun static void ccgr_init(void)
572*4882a593Smuzhiyun {
573*4882a593Smuzhiyun struct mxc_ccm_reg *ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
574*4882a593Smuzhiyun
575*4882a593Smuzhiyun writel(0x00C03F3F, &ccm->CCGR0);
576*4882a593Smuzhiyun writel(0x0030FC03, &ccm->CCGR1);
577*4882a593Smuzhiyun writel(0x0FFFC000, &ccm->CCGR2);
578*4882a593Smuzhiyun writel(0x3FF00000, &ccm->CCGR3);
579*4882a593Smuzhiyun writel(0x00FFF300, &ccm->CCGR4);
580*4882a593Smuzhiyun writel(0x0F0000C3, &ccm->CCGR5);
581*4882a593Smuzhiyun writel(0x000003FF, &ccm->CCGR6);
582*4882a593Smuzhiyun }
583*4882a593Smuzhiyun
spl_dram_init(int width)584*4882a593Smuzhiyun static void spl_dram_init(int width)
585*4882a593Smuzhiyun {
586*4882a593Smuzhiyun struct mx6_ddr_sysinfo sysinfo = {
587*4882a593Smuzhiyun /* width of data bus: 0=16, 1=32, 2=64 */
588*4882a593Smuzhiyun .dsize = width / 32,
589*4882a593Smuzhiyun /* config for full 4GB range so that get_mem_size() works */
590*4882a593Smuzhiyun .cs_density = 32, /* 32Gb per CS */
591*4882a593Smuzhiyun .ncs = 1, /* single chip select */
592*4882a593Smuzhiyun .cs1_mirror = 0,
593*4882a593Smuzhiyun .rtt_wr = 1 /*DDR3_RTT_60_OHM*/, /* RTT_Wr = RZQ/4 */
594*4882a593Smuzhiyun .rtt_nom = 1 /*DDR3_RTT_60_OHM*/, /* RTT_Nom = RZQ/4 */
595*4882a593Smuzhiyun .walat = 1, /* Write additional latency */
596*4882a593Smuzhiyun .ralat = 5, /* Read additional latency */
597*4882a593Smuzhiyun .mif3_mode = 3, /* Command prediction working mode */
598*4882a593Smuzhiyun .bi_on = 1, /* Bank interleaving enabled */
599*4882a593Smuzhiyun .sde_to_rst = 0x10, /* 14 cycles, 200us (JEDEC default) */
600*4882a593Smuzhiyun .rst_to_cke = 0x23, /* 33 cycles, 500us (JEDEC default) */
601*4882a593Smuzhiyun .ddr_type = DDR_TYPE_DDR3,
602*4882a593Smuzhiyun .refsel = 1, /* Refresh cycles at 32KHz */
603*4882a593Smuzhiyun .refr = 7, /* 8 refresh commands per refresh cycle */
604*4882a593Smuzhiyun };
605*4882a593Smuzhiyun
606*4882a593Smuzhiyun if (is_mx6dq())
607*4882a593Smuzhiyun mx6dq_dram_iocfg(width, &mx6q_ddr_ioregs, &mx6q_grp_ioregs);
608*4882a593Smuzhiyun else
609*4882a593Smuzhiyun mx6sdl_dram_iocfg(width, &mx6dl_ddr_ioregs, &mx6sdl_grp_ioregs);
610*4882a593Smuzhiyun
611*4882a593Smuzhiyun if (is_cpu_type(MXC_CPU_MX6D))
612*4882a593Smuzhiyun mx6_dram_cfg(&sysinfo, &mx6q_1g_mmcd_calib, &mem_ddr_2g);
613*4882a593Smuzhiyun else if (is_cpu_type(MXC_CPU_MX6Q))
614*4882a593Smuzhiyun mx6_dram_cfg(&sysinfo, &mx6q_2g_mmcd_calib, &mem_ddr_4g);
615*4882a593Smuzhiyun else if (is_cpu_type(MXC_CPU_MX6DL))
616*4882a593Smuzhiyun mx6_dram_cfg(&sysinfo, &mx6dl_1g_mmcd_calib, &mem_ddr_2g);
617*4882a593Smuzhiyun else if (is_cpu_type(MXC_CPU_MX6SOLO))
618*4882a593Smuzhiyun mx6_dram_cfg(&sysinfo, &mx6dl_512m_mmcd_calib, &mem_ddr_2g);
619*4882a593Smuzhiyun }
620*4882a593Smuzhiyun
board_init_f(ulong dummy)621*4882a593Smuzhiyun void board_init_f(ulong dummy)
622*4882a593Smuzhiyun {
623*4882a593Smuzhiyun /* setup AIPS and disable watchdog */
624*4882a593Smuzhiyun arch_cpu_init();
625*4882a593Smuzhiyun
626*4882a593Smuzhiyun ccgr_init();
627*4882a593Smuzhiyun gpr_init();
628*4882a593Smuzhiyun
629*4882a593Smuzhiyun /* iomux and setup of i2c */
630*4882a593Smuzhiyun board_early_init_f();
631*4882a593Smuzhiyun
632*4882a593Smuzhiyun /* setup GP timer */
633*4882a593Smuzhiyun timer_init();
634*4882a593Smuzhiyun
635*4882a593Smuzhiyun /* UART clocks enabled and gd valid - init serial console */
636*4882a593Smuzhiyun preloader_console_init();
637*4882a593Smuzhiyun
638*4882a593Smuzhiyun /* DDR initialization */
639*4882a593Smuzhiyun if (is_cpu_type(MXC_CPU_MX6SOLO))
640*4882a593Smuzhiyun spl_dram_init(32);
641*4882a593Smuzhiyun else
642*4882a593Smuzhiyun spl_dram_init(64);
643*4882a593Smuzhiyun
644*4882a593Smuzhiyun /* Clear the BSS. */
645*4882a593Smuzhiyun memset(__bss_start, 0, __bss_end - __bss_start);
646*4882a593Smuzhiyun
647*4882a593Smuzhiyun /* load/boot image from boot device */
648*4882a593Smuzhiyun board_init_r(NULL, 0);
649*4882a593Smuzhiyun }
650*4882a593Smuzhiyun #endif
651