uboot/board/sunxi/board.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * (C) Copyright 2012-2013 Henrik Nordstrom <henrik@henriknordstrom.net>
   4 * (C) Copyright 2013 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
   5 *
   6 * (C) Copyright 2007-2011
   7 * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
   8 * Tom Cubie <tangliang@allwinnertech.com>
   9 *
  10 * Some board init for the Allwinner A10-evb board.
  11 */
  12
  13#include <common.h>
  14#include <clock_legacy.h>
  15#include <dm.h>
  16#include <env.h>
  17#include <hang.h>
  18#include <image.h>
  19#include <init.h>
  20#include <log.h>
  21#include <mmc.h>
  22#include <axp_pmic.h>
  23#include <generic-phy.h>
  24#include <phy-sun4i-usb.h>
  25#include <asm/arch/clock.h>
  26#include <asm/arch/cpu.h>
  27#include <asm/arch/display.h>
  28#include <asm/arch/dram.h>
  29#include <asm/arch/mmc.h>
  30#include <asm/arch/prcm.h>
  31#include <asm/arch/pmic_bus.h>
  32#include <asm/arch/spl.h>
  33#include <asm/arch/sys_proto.h>
  34#include <asm/global_data.h>
  35#include <linux/delay.h>
  36#include <u-boot/crc.h>
  37#ifndef CONFIG_ARM64
  38#include <asm/armv7.h>
  39#endif
  40#include <asm/gpio.h>
  41#include <asm/io.h>
  42#include <u-boot/crc.h>
  43#include <env_internal.h>
  44#include <linux/libfdt.h>
  45#include <fdt_support.h>
  46#include <nand.h>
  47#include <net.h>
  48#include <spl.h>
  49#include <sy8106a.h>
  50#include <asm/setup.h>
  51#include <status_led.h>
  52
  53DECLARE_GLOBAL_DATA_PTR;
  54
  55void i2c_init_board(void)
  56{
  57#ifdef CONFIG_I2C0_ENABLE
  58#if defined(CONFIG_MACH_SUN4I) || \
  59    defined(CONFIG_MACH_SUN5I) || \
  60    defined(CONFIG_MACH_SUN7I) || \
  61    defined(CONFIG_MACH_SUN8I_R40)
  62        sunxi_gpio_set_cfgpin(SUNXI_GPB(0), SUN4I_GPB_TWI0);
  63        sunxi_gpio_set_cfgpin(SUNXI_GPB(1), SUN4I_GPB_TWI0);
  64        clock_twi_onoff(0, 1);
  65#elif defined(CONFIG_MACH_SUN6I)
  66        sunxi_gpio_set_cfgpin(SUNXI_GPH(14), SUN6I_GPH_TWI0);
  67        sunxi_gpio_set_cfgpin(SUNXI_GPH(15), SUN6I_GPH_TWI0);
  68        clock_twi_onoff(0, 1);
  69#elif defined(CONFIG_MACH_SUN8I_V3S)
  70        sunxi_gpio_set_cfgpin(SUNXI_GPB(6), SUN8I_V3S_GPB_TWI0);
  71        sunxi_gpio_set_cfgpin(SUNXI_GPB(7), SUN8I_V3S_GPB_TWI0);
  72        clock_twi_onoff(0, 1);
  73#elif defined(CONFIG_MACH_SUN8I)
  74        sunxi_gpio_set_cfgpin(SUNXI_GPH(2), SUN8I_GPH_TWI0);
  75        sunxi_gpio_set_cfgpin(SUNXI_GPH(3), SUN8I_GPH_TWI0);
  76        clock_twi_onoff(0, 1);
  77#elif defined(CONFIG_MACH_SUN50I)
  78        sunxi_gpio_set_cfgpin(SUNXI_GPH(0), SUN50I_GPH_TWI0);
  79        sunxi_gpio_set_cfgpin(SUNXI_GPH(1), SUN50I_GPH_TWI0);
  80        clock_twi_onoff(0, 1);
  81#endif
  82#endif
  83
  84#ifdef CONFIG_I2C1_ENABLE
  85#if defined(CONFIG_MACH_SUN4I) || \
  86    defined(CONFIG_MACH_SUN7I) || \
  87    defined(CONFIG_MACH_SUN8I_R40)
  88        sunxi_gpio_set_cfgpin(SUNXI_GPB(18), SUN4I_GPB_TWI1);
  89        sunxi_gpio_set_cfgpin(SUNXI_GPB(19), SUN4I_GPB_TWI1);
  90        clock_twi_onoff(1, 1);
  91#elif defined(CONFIG_MACH_SUN5I)
  92        sunxi_gpio_set_cfgpin(SUNXI_GPB(15), SUN5I_GPB_TWI1);
  93        sunxi_gpio_set_cfgpin(SUNXI_GPB(16), SUN5I_GPB_TWI1);
  94        clock_twi_onoff(1, 1);
  95#elif defined(CONFIG_MACH_SUN6I)
  96        sunxi_gpio_set_cfgpin(SUNXI_GPH(16), SUN6I_GPH_TWI1);
  97        sunxi_gpio_set_cfgpin(SUNXI_GPH(17), SUN6I_GPH_TWI1);
  98        clock_twi_onoff(1, 1);
  99#elif defined(CONFIG_MACH_SUN8I)
 100        sunxi_gpio_set_cfgpin(SUNXI_GPH(4), SUN8I_GPH_TWI1);
 101        sunxi_gpio_set_cfgpin(SUNXI_GPH(5), SUN8I_GPH_TWI1);
 102        clock_twi_onoff(1, 1);
 103#elif defined(CONFIG_MACH_SUN50I)
 104        sunxi_gpio_set_cfgpin(SUNXI_GPH(2), SUN50I_GPH_TWI1);
 105        sunxi_gpio_set_cfgpin(SUNXI_GPH(3), SUN50I_GPH_TWI1);
 106        clock_twi_onoff(1, 1);
 107#endif
 108#endif
 109
 110#ifdef CONFIG_I2C2_ENABLE
 111#if defined(CONFIG_MACH_SUN4I) || \
 112    defined(CONFIG_MACH_SUN7I) || \
 113    defined(CONFIG_MACH_SUN8I_R40)
 114        sunxi_gpio_set_cfgpin(SUNXI_GPB(20), SUN4I_GPB_TWI2);
 115        sunxi_gpio_set_cfgpin(SUNXI_GPB(21), SUN4I_GPB_TWI2);
 116        clock_twi_onoff(2, 1);
 117#elif defined(CONFIG_MACH_SUN5I)
 118        sunxi_gpio_set_cfgpin(SUNXI_GPB(17), SUN5I_GPB_TWI2);
 119        sunxi_gpio_set_cfgpin(SUNXI_GPB(18), SUN5I_GPB_TWI2);
 120        clock_twi_onoff(2, 1);
 121#elif defined(CONFIG_MACH_SUN6I)
 122        sunxi_gpio_set_cfgpin(SUNXI_GPH(18), SUN6I_GPH_TWI2);
 123        sunxi_gpio_set_cfgpin(SUNXI_GPH(19), SUN6I_GPH_TWI2);
 124        clock_twi_onoff(2, 1);
 125#elif defined(CONFIG_MACH_SUN8I)
 126        sunxi_gpio_set_cfgpin(SUNXI_GPE(12), SUN8I_GPE_TWI2);
 127        sunxi_gpio_set_cfgpin(SUNXI_GPE(13), SUN8I_GPE_TWI2);
 128        clock_twi_onoff(2, 1);
 129#elif defined(CONFIG_MACH_SUN50I)
 130        sunxi_gpio_set_cfgpin(SUNXI_GPE(14), SUN50I_GPE_TWI2);
 131        sunxi_gpio_set_cfgpin(SUNXI_GPE(15), SUN50I_GPE_TWI2);
 132        clock_twi_onoff(2, 1);
 133#endif
 134#endif
 135
 136#ifdef CONFIG_I2C3_ENABLE
 137#if defined(CONFIG_MACH_SUN6I)
 138        sunxi_gpio_set_cfgpin(SUNXI_GPG(10), SUN6I_GPG_TWI3);
 139        sunxi_gpio_set_cfgpin(SUNXI_GPG(11), SUN6I_GPG_TWI3);
 140        clock_twi_onoff(3, 1);
 141#elif defined(CONFIG_MACH_SUN7I) || \
 142      defined(CONFIG_MACH_SUN8I_R40)
 143        sunxi_gpio_set_cfgpin(SUNXI_GPI(0), SUN7I_GPI_TWI3);
 144        sunxi_gpio_set_cfgpin(SUNXI_GPI(1), SUN7I_GPI_TWI3);
 145        clock_twi_onoff(3, 1);
 146#endif
 147#endif
 148
 149#ifdef CONFIG_I2C4_ENABLE
 150#if defined(CONFIG_MACH_SUN7I) || \
 151    defined(CONFIG_MACH_SUN8I_R40)
 152        sunxi_gpio_set_cfgpin(SUNXI_GPI(2), SUN7I_GPI_TWI4);
 153        sunxi_gpio_set_cfgpin(SUNXI_GPI(3), SUN7I_GPI_TWI4);
 154        clock_twi_onoff(4, 1);
 155#endif
 156#endif
 157
 158#ifdef CONFIG_R_I2C_ENABLE
 159#ifdef CONFIG_MACH_SUN50I
 160        clock_twi_onoff(5, 1);
 161        sunxi_gpio_set_cfgpin(SUNXI_GPL(8), SUN50I_GPL_R_TWI);
 162        sunxi_gpio_set_cfgpin(SUNXI_GPL(9), SUN50I_GPL_R_TWI);
 163#elif CONFIG_MACH_SUN50I_H616
 164        clock_twi_onoff(5, 1);
 165        sunxi_gpio_set_cfgpin(SUNXI_GPL(0), SUN50I_H616_GPL_R_TWI);
 166        sunxi_gpio_set_cfgpin(SUNXI_GPL(1), SUN50I_H616_GPL_R_TWI);
 167#else
 168        clock_twi_onoff(5, 1);
 169        sunxi_gpio_set_cfgpin(SUNXI_GPL(0), SUN8I_H3_GPL_R_TWI);
 170        sunxi_gpio_set_cfgpin(SUNXI_GPL(1), SUN8I_H3_GPL_R_TWI);
 171#endif
 172#endif
 173}
 174
 175/*
 176 * Try to use the environment from the boot source first.
 177 * For MMC, this means a FAT partition on the boot device (SD or eMMC).
 178 * If the raw MMC environment is also enabled, this is tried next.
 179 * SPI flash falls back to FAT (on SD card).
 180 */
 181enum env_location env_get_location(enum env_operation op, int prio)
 182{
 183        enum env_location boot_loc = ENVL_FAT;
 184
 185        gd->env_load_prio = prio;
 186
 187        switch (sunxi_get_boot_device()) {
 188        case BOOT_DEVICE_MMC1:
 189        case BOOT_DEVICE_MMC2:
 190                boot_loc = ENVL_FAT;
 191                break;
 192        case BOOT_DEVICE_NAND:
 193                if (IS_ENABLED(CONFIG_ENV_IS_IN_NAND))
 194                        boot_loc = ENVL_NAND;
 195                break;
 196        case BOOT_DEVICE_SPI:
 197                if (IS_ENABLED(CONFIG_ENV_IS_IN_SPI_FLASH))
 198                        boot_loc = ENVL_SPI_FLASH;
 199                break;
 200        case BOOT_DEVICE_BOARD:
 201                break;
 202        default:
 203                break;
 204        }
 205
 206        /* Always try to access the environment on the boot device first. */
 207        if (prio == 0)
 208                return boot_loc;
 209
 210        if (prio == 1) {
 211                switch (boot_loc) {
 212                case ENVL_SPI_FLASH:
 213                        return ENVL_FAT;
 214                case ENVL_FAT:
 215                        if (IS_ENABLED(CONFIG_ENV_IS_IN_MMC))
 216                                return ENVL_MMC;
 217                        break;
 218                default:
 219                        break;
 220                }
 221        }
 222
 223        return ENVL_UNKNOWN;
 224}
 225
 226#ifdef CONFIG_DM_MMC
 227static void mmc_pinmux_setup(int sdc);
 228#endif
 229
 230/* add board specific code here */
 231int board_init(void)
 232{
 233        __maybe_unused int id_pfr1, ret, satapwr_pin, macpwr_pin;
 234
 235        gd->bd->bi_boot_params = (PHYS_SDRAM_0 + 0x100);
 236
 237#if !defined(CONFIG_ARM64) && !defined(CONFIG_MACH_SUNIV)
 238        asm volatile("mrc p15, 0, %0, c0, c1, 1" : "=r"(id_pfr1));
 239        debug("id_pfr1: 0x%08x\n", id_pfr1);
 240        /* Generic Timer Extension available? */
 241        if ((id_pfr1 >> CPUID_ARM_GENTIMER_SHIFT) & 0xf) {
 242                uint32_t freq;
 243
 244                debug("Setting CNTFRQ\n");
 245
 246                /*
 247                 * CNTFRQ is a secure register, so we will crash if we try to
 248                 * write this from the non-secure world (read is OK, though).
 249                 * In case some bootcode has already set the correct value,
 250                 * we avoid the risk of writing to it.
 251                 */
 252                asm volatile("mrc p15, 0, %0, c14, c0, 0" : "=r"(freq));
 253                if (freq != COUNTER_FREQUENCY) {
 254                        debug("arch timer frequency is %d Hz, should be %d, fixing ...\n",
 255                              freq, COUNTER_FREQUENCY);
 256#ifdef CONFIG_NON_SECURE
 257                        printf("arch timer frequency is wrong, but cannot adjust it\n");
 258#else
 259                        asm volatile("mcr p15, 0, %0, c14, c0, 0"
 260                                     : : "r"(COUNTER_FREQUENCY));
 261#endif
 262                }
 263        }
 264#endif /* !CONFIG_ARM64 && !CONFIG_MACH_SUNIV */
 265
 266        ret = axp_gpio_init();
 267        if (ret)
 268                return ret;
 269
 270        /* strcmp() would look better, but doesn't get optimised away. */
 271        if (CONFIG_SATAPWR[0]) {
 272                satapwr_pin = sunxi_name_to_gpio(CONFIG_SATAPWR);
 273                if (satapwr_pin >= 0) {
 274                        gpio_request(satapwr_pin, "satapwr");
 275                        gpio_direction_output(satapwr_pin, 1);
 276
 277                        /*
 278                         * Give the attached SATA device time to power-up
 279                         * to avoid link timeouts
 280                         */
 281                        mdelay(500);
 282                }
 283        }
 284
 285        if (CONFIG_MACPWR[0]) {
 286                macpwr_pin = sunxi_name_to_gpio(CONFIG_MACPWR);
 287                if (macpwr_pin >= 0) {
 288                        gpio_request(macpwr_pin, "macpwr");
 289                        gpio_direction_output(macpwr_pin, 1);
 290                }
 291        }
 292
 293#if CONFIG_IS_ENABLED(DM_I2C)
 294        /*
 295         * Temporary workaround for enabling I2C clocks until proper sunxi DM
 296         * clk, reset and pinctrl drivers land.
 297         */
 298        i2c_init_board();
 299#endif
 300
 301#ifdef CONFIG_DM_MMC
 302        /*
 303         * Temporary workaround for enabling MMC clocks until a sunxi DM
 304         * pinctrl driver lands.
 305         */
 306        mmc_pinmux_setup(CONFIG_MMC_SUNXI_SLOT);
 307#if CONFIG_MMC_SUNXI_SLOT_EXTRA != -1
 308        mmc_pinmux_setup(CONFIG_MMC_SUNXI_SLOT_EXTRA);
 309#endif
 310#endif  /* CONFIG_DM_MMC */
 311
 312        eth_init_board();
 313
 314        return 0;
 315}
 316
 317/*
 318 * On older SoCs the SPL is actually at address zero, so using NULL as
 319 * an error value does not work.
 320 */
 321#define INVALID_SPL_HEADER ((void *)~0UL)
 322
 323static struct boot_file_head * get_spl_header(uint8_t req_version)
 324{
 325        struct boot_file_head *spl = (void *)(ulong)SPL_ADDR;
 326        uint8_t spl_header_version = spl->spl_signature[3];
 327
 328        /* Is there really the SPL header (still) there? */
 329        if (memcmp(spl->spl_signature, SPL_SIGNATURE, 3) != 0)
 330                return INVALID_SPL_HEADER;
 331
 332        if (spl_header_version < req_version) {
 333                printf("sunxi SPL version mismatch: expected %u, got %u\n",
 334                       req_version, spl_header_version);
 335                return INVALID_SPL_HEADER;
 336        }
 337
 338        return spl;
 339}
 340
 341static const char *get_spl_dt_name(void)
 342{
 343        struct boot_file_head *spl = get_spl_header(SPL_DT_HEADER_VERSION);
 344
 345        /* Check if there is a DT name stored in the SPL header. */
 346        if (spl != INVALID_SPL_HEADER && spl->dt_name_offset)
 347                return (char *)spl + spl->dt_name_offset;
 348
 349        return NULL;
 350}
 351
 352int dram_init(void)
 353{
 354        struct boot_file_head *spl = get_spl_header(SPL_DRAM_HEADER_VERSION);
 355
 356        if (spl == INVALID_SPL_HEADER)
 357                gd->ram_size = get_ram_size((long *)PHYS_SDRAM_0,
 358                                            PHYS_SDRAM_0_SIZE);
 359        else
 360                gd->ram_size = (phys_addr_t)spl->dram_size << 20;
 361
 362        if (gd->ram_size > CONFIG_SUNXI_DRAM_MAX_SIZE)
 363                gd->ram_size = CONFIG_SUNXI_DRAM_MAX_SIZE;
 364
 365        return 0;
 366}
 367
 368#if defined(CONFIG_NAND_SUNXI)
 369static void nand_pinmux_setup(void)
 370{
 371        unsigned int pin;
 372
 373        for (pin = SUNXI_GPC(0); pin <= SUNXI_GPC(19); pin++)
 374                sunxi_gpio_set_cfgpin(pin, SUNXI_GPC_NAND);
 375
 376#if defined CONFIG_MACH_SUN4I || defined CONFIG_MACH_SUN7I
 377        for (pin = SUNXI_GPC(20); pin <= SUNXI_GPC(22); pin++)
 378                sunxi_gpio_set_cfgpin(pin, SUNXI_GPC_NAND);
 379#endif
 380        /* sun4i / sun7i do have a PC23, but it is not used for nand,
 381         * only sun7i has a PC24 */
 382#ifdef CONFIG_MACH_SUN7I
 383        sunxi_gpio_set_cfgpin(SUNXI_GPC(24), SUNXI_GPC_NAND);
 384#endif
 385}
 386
 387static void nand_clock_setup(void)
 388{
 389        struct sunxi_ccm_reg *const ccm =
 390                (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
 391
 392        setbits_le32(&ccm->ahb_gate0, (CLK_GATE_OPEN << AHB_GATE_OFFSET_NAND0));
 393#if defined CONFIG_MACH_SUN6I || defined CONFIG_MACH_SUN8I || \
 394    defined CONFIG_MACH_SUN9I || defined CONFIG_MACH_SUN50I
 395        setbits_le32(&ccm->ahb_reset0_cfg, (1 << AHB_GATE_OFFSET_NAND0));
 396#endif
 397        setbits_le32(&ccm->nand0_clk_cfg, CCM_NAND_CTRL_ENABLE | AHB_DIV_1);
 398}
 399
 400void board_nand_init(void)
 401{
 402        nand_pinmux_setup();
 403        nand_clock_setup();
 404#ifndef CONFIG_SPL_BUILD
 405        sunxi_nand_init();
 406#endif
 407}
 408#endif
 409
 410#ifdef CONFIG_MMC
 411static void mmc_pinmux_setup(int sdc)
 412{
 413        unsigned int pin;
 414
 415        switch (sdc) {
 416        case 0:
 417                /* SDC0: PF0-PF5 */
 418                for (pin = SUNXI_GPF(0); pin <= SUNXI_GPF(5); pin++) {
 419                        sunxi_gpio_set_cfgpin(pin, SUNXI_GPF_SDC0);
 420                        sunxi_gpio_set_pull(pin, SUNXI_GPIO_PULL_UP);
 421                        sunxi_gpio_set_drv(pin, 2);
 422                }
 423                break;
 424
 425        case 1:
 426#if defined(CONFIG_MACH_SUN4I) || defined(CONFIG_MACH_SUN7I) || \
 427    defined(CONFIG_MACH_SUN8I_R40)
 428                if (IS_ENABLED(CONFIG_MMC1_PINS_PH)) {
 429                        /* SDC1: PH22-PH-27 */
 430                        for (pin = SUNXI_GPH(22); pin <= SUNXI_GPH(27); pin++) {
 431                                sunxi_gpio_set_cfgpin(pin, SUN4I_GPH_SDC1);
 432                                sunxi_gpio_set_pull(pin, SUNXI_GPIO_PULL_UP);
 433                                sunxi_gpio_set_drv(pin, 2);
 434                        }
 435                } else {
 436                        /* SDC1: PG0-PG5 */
 437                        for (pin = SUNXI_GPG(0); pin <= SUNXI_GPG(5); pin++) {
 438                                sunxi_gpio_set_cfgpin(pin, SUN4I_GPG_SDC1);
 439                                sunxi_gpio_set_pull(pin, SUNXI_GPIO_PULL_UP);
 440                                sunxi_gpio_set_drv(pin, 2);
 441                        }
 442                }
 443#elif defined(CONFIG_MACH_SUN5I)
 444                /* SDC1: PG3-PG8 */
 445                for (pin = SUNXI_GPG(3); pin <= SUNXI_GPG(8); pin++) {
 446                        sunxi_gpio_set_cfgpin(pin, SUN5I_GPG_SDC1);
 447                        sunxi_gpio_set_pull(pin, SUNXI_GPIO_PULL_UP);
 448                        sunxi_gpio_set_drv(pin, 2);
 449                }
 450#elif defined(CONFIG_MACH_SUN6I)
 451                /* SDC1: PG0-PG5 */
 452                for (pin = SUNXI_GPG(0); pin <= SUNXI_GPG(5); pin++) {
 453                        sunxi_gpio_set_cfgpin(pin, SUN6I_GPG_SDC1);
 454                        sunxi_gpio_set_pull(pin, SUNXI_GPIO_PULL_UP);
 455                        sunxi_gpio_set_drv(pin, 2);
 456                }
 457#elif defined(CONFIG_MACH_SUN8I)
 458                /* SDC1: PG0-PG5 */
 459                for (pin = SUNXI_GPG(0); pin <= SUNXI_GPG(5); pin++) {
 460                        sunxi_gpio_set_cfgpin(pin, SUN8I_GPG_SDC1);
 461                        sunxi_gpio_set_pull(pin, SUNXI_GPIO_PULL_UP);
 462                        sunxi_gpio_set_drv(pin, 2);
 463                }
 464#endif
 465                break;
 466
 467        case 2:
 468#if defined(CONFIG_MACH_SUN4I) || defined(CONFIG_MACH_SUN7I)
 469                /* SDC2: PC6-PC11 */
 470                for (pin = SUNXI_GPC(6); pin <= SUNXI_GPC(11); pin++) {
 471                        sunxi_gpio_set_cfgpin(pin, SUNXI_GPC_SDC2);
 472                        sunxi_gpio_set_pull(pin, SUNXI_GPIO_PULL_UP);
 473                        sunxi_gpio_set_drv(pin, 2);
 474                }
 475#elif defined(CONFIG_MACH_SUN5I)
 476                /* SDC2: PC6-PC15 */
 477                for (pin = SUNXI_GPC(6); pin <= SUNXI_GPC(15); pin++) {
 478                        sunxi_gpio_set_cfgpin(pin, SUNXI_GPC_SDC2);
 479                        sunxi_gpio_set_pull(pin, SUNXI_GPIO_PULL_UP);
 480                        sunxi_gpio_set_drv(pin, 2);
 481                }
 482#elif defined(CONFIG_MACH_SUN6I)
 483                /* SDC2: PC6-PC15, PC24 */
 484                for (pin = SUNXI_GPC(6); pin <= SUNXI_GPC(15); pin++) {
 485                        sunxi_gpio_set_cfgpin(pin, SUNXI_GPC_SDC2);
 486                        sunxi_gpio_set_pull(pin, SUNXI_GPIO_PULL_UP);
 487                        sunxi_gpio_set_drv(pin, 2);
 488                }
 489
 490                sunxi_gpio_set_cfgpin(SUNXI_GPC(24), SUNXI_GPC_SDC2);
 491                sunxi_gpio_set_pull(SUNXI_GPC(24), SUNXI_GPIO_PULL_UP);
 492                sunxi_gpio_set_drv(SUNXI_GPC(24), 2);
 493#elif defined(CONFIG_MACH_SUN8I_R40)
 494                /* SDC2: PC6-PC15, PC24 */
 495                for (pin = SUNXI_GPC(6); pin <= SUNXI_GPC(15); pin++) {
 496                        sunxi_gpio_set_cfgpin(pin, SUNXI_GPC_SDC2);
 497                        sunxi_gpio_set_pull(pin, SUNXI_GPIO_PULL_UP);
 498                        sunxi_gpio_set_drv(pin, 2);
 499                }
 500
 501                sunxi_gpio_set_cfgpin(SUNXI_GPC(24), SUNXI_GPC_SDC2);
 502                sunxi_gpio_set_pull(SUNXI_GPC(24), SUNXI_GPIO_PULL_UP);
 503                sunxi_gpio_set_drv(SUNXI_GPC(24), 2);
 504#elif defined(CONFIG_MACH_SUN8I) || defined(CONFIG_MACH_SUN50I)
 505                /* SDC2: PC5-PC6, PC8-PC16 */
 506                for (pin = SUNXI_GPC(5); pin <= SUNXI_GPC(6); pin++) {
 507                        sunxi_gpio_set_cfgpin(pin, SUNXI_GPC_SDC2);
 508                        sunxi_gpio_set_pull(pin, SUNXI_GPIO_PULL_UP);
 509                        sunxi_gpio_set_drv(pin, 2);
 510                }
 511
 512                for (pin = SUNXI_GPC(8); pin <= SUNXI_GPC(16); pin++) {
 513                        sunxi_gpio_set_cfgpin(pin, SUNXI_GPC_SDC2);
 514                        sunxi_gpio_set_pull(pin, SUNXI_GPIO_PULL_UP);
 515                        sunxi_gpio_set_drv(pin, 2);
 516                }
 517#elif defined(CONFIG_MACH_SUN50I_H6)
 518                /* SDC2: PC4-PC14 */
 519                for (pin = SUNXI_GPC(4); pin <= SUNXI_GPC(14); pin++) {
 520                        sunxi_gpio_set_cfgpin(pin, SUNXI_GPC_SDC2);
 521                        sunxi_gpio_set_pull(pin, SUNXI_GPIO_PULL_UP);
 522                        sunxi_gpio_set_drv(pin, 2);
 523                }
 524#elif defined(CONFIG_MACH_SUN50I_H616)
 525                /* SDC2: PC0-PC1, PC5-PC6, PC8-PC11, PC13-PC16 */
 526                for (pin = SUNXI_GPC(0); pin <= SUNXI_GPC(16); pin++) {
 527                        if (pin > SUNXI_GPC(1) && pin < SUNXI_GPC(5))
 528                                continue;
 529                        if (pin == SUNXI_GPC(7) || pin == SUNXI_GPC(12))
 530                                continue;
 531                        sunxi_gpio_set_cfgpin(pin, SUNXI_GPC_SDC2);
 532                        sunxi_gpio_set_pull(pin, SUNXI_GPIO_PULL_UP);
 533                        sunxi_gpio_set_drv(pin, 3);
 534                }
 535#elif defined(CONFIG_MACH_SUN9I)
 536                /* SDC2: PC6-PC16 */
 537                for (pin = SUNXI_GPC(6); pin <= SUNXI_GPC(16); pin++) {
 538                        sunxi_gpio_set_cfgpin(pin, SUNXI_GPC_SDC2);
 539                        sunxi_gpio_set_pull(pin, SUNXI_GPIO_PULL_UP);
 540                        sunxi_gpio_set_drv(pin, 2);
 541                }
 542#else
 543                puts("ERROR: No pinmux setup defined for MMC2!\n");
 544#endif
 545                break;
 546
 547        case 3:
 548#if defined(CONFIG_MACH_SUN4I) || defined(CONFIG_MACH_SUN7I) || \
 549    defined(CONFIG_MACH_SUN8I_R40)
 550                /* SDC3: PI4-PI9 */
 551                for (pin = SUNXI_GPI(4); pin <= SUNXI_GPI(9); pin++) {
 552                        sunxi_gpio_set_cfgpin(pin, SUNXI_GPI_SDC3);
 553                        sunxi_gpio_set_pull(pin, SUNXI_GPIO_PULL_UP);
 554                        sunxi_gpio_set_drv(pin, 2);
 555                }
 556#elif defined(CONFIG_MACH_SUN6I)
 557                /* SDC3: PC6-PC15, PC24 */
 558                for (pin = SUNXI_GPC(6); pin <= SUNXI_GPC(15); pin++) {
 559                        sunxi_gpio_set_cfgpin(pin, SUN6I_GPC_SDC3);
 560                        sunxi_gpio_set_pull(pin, SUNXI_GPIO_PULL_UP);
 561                        sunxi_gpio_set_drv(pin, 2);
 562                }
 563
 564                sunxi_gpio_set_cfgpin(SUNXI_GPC(24), SUN6I_GPC_SDC3);
 565                sunxi_gpio_set_pull(SUNXI_GPC(24), SUNXI_GPIO_PULL_UP);
 566                sunxi_gpio_set_drv(SUNXI_GPC(24), 2);
 567#endif
 568                break;
 569
 570        default:
 571                printf("sunxi: invalid MMC slot %d for pinmux setup\n", sdc);
 572                break;
 573        }
 574}
 575
 576int board_mmc_init(struct bd_info *bis)
 577{
 578        __maybe_unused struct mmc *mmc0, *mmc1;
 579
 580        mmc_pinmux_setup(CONFIG_MMC_SUNXI_SLOT);
 581        mmc0 = sunxi_mmc_init(CONFIG_MMC_SUNXI_SLOT);
 582        if (!mmc0)
 583                return -1;
 584
 585#if CONFIG_MMC_SUNXI_SLOT_EXTRA != -1
 586        mmc_pinmux_setup(CONFIG_MMC_SUNXI_SLOT_EXTRA);
 587        mmc1 = sunxi_mmc_init(CONFIG_MMC_SUNXI_SLOT_EXTRA);
 588        if (!mmc1)
 589                return -1;
 590#endif
 591
 592        return 0;
 593}
 594
 595#if CONFIG_MMC_SUNXI_SLOT_EXTRA != -1
 596int mmc_get_env_dev(void)
 597{
 598        switch (sunxi_get_boot_device()) {
 599        case BOOT_DEVICE_MMC1:
 600                return 0;
 601        case BOOT_DEVICE_MMC2:
 602                return 1;
 603        default:
 604                return CONFIG_SYS_MMC_ENV_DEV;
 605        }
 606}
 607#endif
 608#endif
 609
 610#ifdef CONFIG_SPL_BUILD
 611
 612static void sunxi_spl_store_dram_size(phys_addr_t dram_size)
 613{
 614        struct boot_file_head *spl = get_spl_header(SPL_DT_HEADER_VERSION);
 615
 616        if (spl == INVALID_SPL_HEADER)
 617                return;
 618
 619        /* Promote the header version for U-Boot proper, if needed. */
 620        if (spl->spl_signature[3] < SPL_DRAM_HEADER_VERSION)
 621                spl->spl_signature[3] = SPL_DRAM_HEADER_VERSION;
 622
 623        spl->dram_size = dram_size >> 20;
 624}
 625
 626void sunxi_board_init(void)
 627{
 628        int power_failed = 0;
 629
 630#ifdef CONFIG_LED_STATUS
 631        if (IS_ENABLED(CONFIG_SPL_DRIVERS_MISC))
 632                status_led_init();
 633#endif
 634
 635#ifdef CONFIG_SY8106A_POWER
 636        power_failed = sy8106a_set_vout1(CONFIG_SY8106A_VOUT1_VOLT);
 637#endif
 638
 639#if defined CONFIG_AXP152_POWER || defined CONFIG_AXP209_POWER || \
 640        defined CONFIG_AXP221_POWER || defined CONFIG_AXP305_POWER || \
 641        defined CONFIG_AXP809_POWER || defined CONFIG_AXP818_POWER
 642        power_failed = axp_init();
 643
 644        if (IS_ENABLED(CONFIG_AXP_DISABLE_BOOT_ON_POWERON) && !power_failed) {
 645                u8 boot_reason;
 646
 647                pmic_bus_read(AXP_POWER_STATUS, &boot_reason);
 648                if (boot_reason & AXP_POWER_STATUS_ALDO_IN) {
 649                        printf("Power on by plug-in, shutting down.\n");
 650                        pmic_bus_write(0x32, BIT(7));
 651                }
 652        }
 653
 654#if defined CONFIG_AXP221_POWER || defined CONFIG_AXP809_POWER || \
 655        defined CONFIG_AXP818_POWER
 656        power_failed |= axp_set_dcdc1(CONFIG_AXP_DCDC1_VOLT);
 657#endif
 658#if !defined(CONFIG_AXP305_POWER)
 659        power_failed |= axp_set_dcdc2(CONFIG_AXP_DCDC2_VOLT);
 660        power_failed |= axp_set_dcdc3(CONFIG_AXP_DCDC3_VOLT);
 661#endif
 662#if !defined(CONFIG_AXP209_POWER) && !defined(CONFIG_AXP818_POWER)
 663        power_failed |= axp_set_dcdc4(CONFIG_AXP_DCDC4_VOLT);
 664#endif
 665#if defined CONFIG_AXP221_POWER || defined CONFIG_AXP809_POWER || \
 666        defined CONFIG_AXP818_POWER
 667        power_failed |= axp_set_dcdc5(CONFIG_AXP_DCDC5_VOLT);
 668#endif
 669
 670#if defined CONFIG_AXP221_POWER || defined CONFIG_AXP809_POWER || \
 671        defined CONFIG_AXP818_POWER
 672        power_failed |= axp_set_aldo1(CONFIG_AXP_ALDO1_VOLT);
 673#endif
 674#if !defined(CONFIG_AXP305_POWER)
 675        power_failed |= axp_set_aldo2(CONFIG_AXP_ALDO2_VOLT);
 676#endif
 677#if !defined(CONFIG_AXP152_POWER) && !defined(CONFIG_AXP305_POWER)
 678        power_failed |= axp_set_aldo3(CONFIG_AXP_ALDO3_VOLT);
 679#endif
 680#ifdef CONFIG_AXP209_POWER
 681        power_failed |= axp_set_aldo4(CONFIG_AXP_ALDO4_VOLT);
 682#endif
 683
 684#if defined(CONFIG_AXP221_POWER) || defined(CONFIG_AXP809_POWER) || \
 685        defined(CONFIG_AXP818_POWER)
 686        power_failed |= axp_set_dldo(1, CONFIG_AXP_DLDO1_VOLT);
 687        power_failed |= axp_set_dldo(2, CONFIG_AXP_DLDO2_VOLT);
 688#if !defined CONFIG_AXP809_POWER
 689        power_failed |= axp_set_dldo(3, CONFIG_AXP_DLDO3_VOLT);
 690        power_failed |= axp_set_dldo(4, CONFIG_AXP_DLDO4_VOLT);
 691#endif
 692        power_failed |= axp_set_eldo(1, CONFIG_AXP_ELDO1_VOLT);
 693        power_failed |= axp_set_eldo(2, CONFIG_AXP_ELDO2_VOLT);
 694        power_failed |= axp_set_eldo(3, CONFIG_AXP_ELDO3_VOLT);
 695#endif
 696
 697#ifdef CONFIG_AXP818_POWER
 698        power_failed |= axp_set_fldo(1, CONFIG_AXP_FLDO1_VOLT);
 699        power_failed |= axp_set_fldo(2, CONFIG_AXP_FLDO2_VOLT);
 700        power_failed |= axp_set_fldo(3, CONFIG_AXP_FLDO3_VOLT);
 701#endif
 702
 703#if defined CONFIG_AXP809_POWER || defined CONFIG_AXP818_POWER
 704        power_failed |= axp_set_sw(IS_ENABLED(CONFIG_AXP_SW_ON));
 705#endif
 706#endif
 707        printf("DRAM:");
 708        gd->ram_size = sunxi_dram_init();
 709        printf(" %d MiB\n", (int)(gd->ram_size >> 20));
 710        if (!gd->ram_size)
 711                hang();
 712
 713        sunxi_spl_store_dram_size(gd->ram_size);
 714
 715        /*
 716         * Only clock up the CPU to full speed if we are reasonably
 717         * assured it's being powered with suitable core voltage
 718         */
 719        if (!power_failed)
 720                clock_set_pll1(get_board_sys_clk());
 721        else
 722                printf("Failed to set core voltage! Can't set CPU frequency\n");
 723}
 724#endif
 725
 726#ifdef CONFIG_USB_GADGET
 727int g_dnl_board_usb_cable_connected(void)
 728{
 729        struct udevice *dev;
 730        struct phy phy;
 731        int ret;
 732
 733        ret = uclass_get_device(UCLASS_USB_GADGET_GENERIC, 0, &dev);
 734        if (ret) {
 735                pr_err("%s: Cannot find USB device\n", __func__);
 736                return ret;
 737        }
 738
 739        ret = generic_phy_get_by_name(dev, "usb", &phy);
 740        if (ret) {
 741                pr_err("failed to get %s USB PHY\n", dev->name);
 742                return ret;
 743        }
 744
 745        ret = generic_phy_init(&phy);
 746        if (ret) {
 747                pr_debug("failed to init %s USB PHY\n", dev->name);
 748                return ret;
 749        }
 750
 751        return sun4i_usb_phy_vbus_detect(&phy);
 752}
 753#endif
 754
 755#ifdef CONFIG_SERIAL_TAG
 756void get_board_serial(struct tag_serialnr *serialnr)
 757{
 758        char *serial_string;
 759        unsigned long long serial;
 760
 761        serial_string = env_get("serial#");
 762
 763        if (serial_string) {
 764                serial = simple_strtoull(serial_string, NULL, 16);
 765
 766                serialnr->high = (unsigned int) (serial >> 32);
 767                serialnr->low = (unsigned int) (serial & 0xffffffff);
 768        } else {
 769                serialnr->high = 0;
 770                serialnr->low = 0;
 771        }
 772}
 773#endif
 774
 775/*
 776 * Check the SPL header for the "sunxi" variant. If found: parse values
 777 * that might have been passed by the loader ("fel" utility), and update
 778 * the environment accordingly.
 779 */
 780static void parse_spl_header(const uint32_t spl_addr)
 781{
 782        struct boot_file_head *spl = get_spl_header(SPL_ENV_HEADER_VERSION);
 783
 784        if (spl == INVALID_SPL_HEADER)
 785                return;
 786
 787        if (!spl->fel_script_address)
 788                return;
 789
 790        if (spl->fel_uEnv_length != 0) {
 791                /*
 792                 * data is expected in uEnv.txt compatible format, so "env
 793                 * import -t" the string(s) at fel_script_address right away.
 794                 */
 795                himport_r(&env_htab, (char *)(uintptr_t)spl->fel_script_address,
 796                          spl->fel_uEnv_length, '\n', H_NOCLEAR, 0, 0, NULL);
 797                return;
 798        }
 799        /* otherwise assume .scr format (mkimage-type script) */
 800        env_set_hex("fel_scriptaddr", spl->fel_script_address);
 801}
 802
 803static bool get_unique_sid(unsigned int *sid)
 804{
 805        if (sunxi_get_sid(sid) != 0)
 806                return false;
 807
 808        if (!sid[0])
 809                return false;
 810
 811        /*
 812         * The single words 1 - 3 of the SID have quite a few bits
 813         * which are the same on many models, so we take a crc32
 814         * of all 3 words, to get a more unique value.
 815         *
 816         * Note we only do this on newer SoCs as we cannot change
 817         * the algorithm on older SoCs since those have been using
 818         * fixed mac-addresses based on only using word 3 for a
 819         * long time and changing a fixed mac-address with an
 820         * u-boot update is not good.
 821         */
 822#if !defined(CONFIG_MACH_SUN4I) && !defined(CONFIG_MACH_SUN5I) && \
 823    !defined(CONFIG_MACH_SUN6I) && !defined(CONFIG_MACH_SUN7I) && \
 824    !defined(CONFIG_MACH_SUN8I_A23) && !defined(CONFIG_MACH_SUN8I_A33)
 825        sid[3] = crc32(0, (unsigned char *)&sid[1], 12);
 826#endif
 827
 828        /* Ensure the NIC specific bytes of the mac are not all 0 */
 829        if ((sid[3] & 0xffffff) == 0)
 830                sid[3] |= 0x800000;
 831
 832        return true;
 833}
 834
 835/*
 836 * Note this function gets called multiple times.
 837 * It must not make any changes to env variables which already exist.
 838 */
 839static void setup_environment(const void *fdt)
 840{
 841        char serial_string[17] = { 0 };
 842        unsigned int sid[4];
 843        uint8_t mac_addr[6];
 844        char ethaddr[16];
 845        int i;
 846
 847        if (!get_unique_sid(sid))
 848                return;
 849
 850        for (i = 0; i < 4; i++) {
 851                sprintf(ethaddr, "ethernet%d", i);
 852                if (!fdt_get_alias(fdt, ethaddr))
 853                        continue;
 854
 855                if (i == 0)
 856                        strcpy(ethaddr, "ethaddr");
 857                else
 858                        sprintf(ethaddr, "eth%daddr", i);
 859
 860                if (env_get(ethaddr))
 861                        continue;
 862
 863                /* Non OUI / registered MAC address */
 864                mac_addr[0] = (i << 4) | 0x02;
 865                mac_addr[1] = (sid[0] >>  0) & 0xff;
 866                mac_addr[2] = (sid[3] >> 24) & 0xff;
 867                mac_addr[3] = (sid[3] >> 16) & 0xff;
 868                mac_addr[4] = (sid[3] >>  8) & 0xff;
 869                mac_addr[5] = (sid[3] >>  0) & 0xff;
 870
 871                eth_env_set_enetaddr(ethaddr, mac_addr);
 872        }
 873
 874        if (!env_get("serial#")) {
 875                snprintf(serial_string, sizeof(serial_string),
 876                        "%08x%08x", sid[0], sid[3]);
 877
 878                env_set("serial#", serial_string);
 879        }
 880}
 881
 882int misc_init_r(void)
 883{
 884        const char *spl_dt_name;
 885        uint boot;
 886
 887        env_set("fel_booted", NULL);
 888        env_set("fel_scriptaddr", NULL);
 889        env_set("mmc_bootdev", NULL);
 890
 891        boot = sunxi_get_boot_device();
 892        /* determine if we are running in FEL mode */
 893        if (boot == BOOT_DEVICE_BOARD) {
 894                env_set("fel_booted", "1");
 895                parse_spl_header(SPL_ADDR);
 896        /* or if we booted from MMC, and which one */
 897        } else if (boot == BOOT_DEVICE_MMC1) {
 898                env_set("mmc_bootdev", "0");
 899        } else if (boot == BOOT_DEVICE_MMC2) {
 900                env_set("mmc_bootdev", "1");
 901        }
 902
 903        /* Set fdtfile to match the FIT configuration chosen in SPL. */
 904        spl_dt_name = get_spl_dt_name();
 905        if (spl_dt_name) {
 906                char *prefix = IS_ENABLED(CONFIG_ARM64) ? "allwinner/" : "";
 907                char str[64];
 908
 909                snprintf(str, sizeof(str), "%s%s.dtb", prefix, spl_dt_name);
 910                env_set("fdtfile", str);
 911        }
 912
 913        setup_environment(gd->fdt_blob);
 914
 915        return 0;
 916}
 917
 918int board_late_init(void)
 919{
 920#ifdef CONFIG_USB_ETHER
 921        usb_ether_init();
 922#endif
 923
 924        return 0;
 925}
 926
 927static void bluetooth_dt_fixup(void *blob)
 928{
 929        /* Some devices ship with a Bluetooth controller default address.
 930         * Set a valid address through the device tree.
 931         */
 932        uchar tmp[ETH_ALEN], bdaddr[ETH_ALEN];
 933        unsigned int sid[4];
 934        int i;
 935
 936        if (!CONFIG_BLUETOOTH_DT_DEVICE_FIXUP[0])
 937                return;
 938
 939        if (eth_env_get_enetaddr("bdaddr", tmp)) {
 940                /* Convert between the binary formats of the corresponding stacks */
 941                for (i = 0; i < ETH_ALEN; ++i)
 942                        bdaddr[i] = tmp[ETH_ALEN - i - 1];
 943        } else {
 944                if (!get_unique_sid(sid))
 945                        return;
 946
 947                bdaddr[0] = ((sid[3] >>  0) & 0xff) ^ 1;
 948                bdaddr[1] = (sid[3] >>  8) & 0xff;
 949                bdaddr[2] = (sid[3] >> 16) & 0xff;
 950                bdaddr[3] = (sid[3] >> 24) & 0xff;
 951                bdaddr[4] = (sid[0] >>  0) & 0xff;
 952                bdaddr[5] = 0x02;
 953        }
 954
 955        do_fixup_by_compat(blob, CONFIG_BLUETOOTH_DT_DEVICE_FIXUP,
 956                           "local-bd-address", bdaddr, ETH_ALEN, 1);
 957}
 958
 959int ft_board_setup(void *blob, struct bd_info *bd)
 960{
 961        int __maybe_unused r;
 962
 963        /*
 964         * Call setup_environment and fdt_fixup_ethernet again
 965         * in case the boot fdt has ethernet aliases the u-boot
 966         * copy does not have.
 967         */
 968        setup_environment(blob);
 969        fdt_fixup_ethernet(blob);
 970
 971        bluetooth_dt_fixup(blob);
 972
 973#ifdef CONFIG_VIDEO_DT_SIMPLEFB
 974        r = sunxi_simplefb_setup(blob);
 975        if (r)
 976                return r;
 977#endif
 978        return 0;
 979}
 980
 981#ifdef CONFIG_SPL_LOAD_FIT
 982
 983static void set_spl_dt_name(const char *name)
 984{
 985        struct boot_file_head *spl = get_spl_header(SPL_ENV_HEADER_VERSION);
 986
 987        if (spl == INVALID_SPL_HEADER)
 988                return;
 989
 990        /* Promote the header version for U-Boot proper, if needed. */
 991        if (spl->spl_signature[3] < SPL_DT_HEADER_VERSION)
 992                spl->spl_signature[3] = SPL_DT_HEADER_VERSION;
 993
 994        strcpy((char *)&spl->string_pool, name);
 995        spl->dt_name_offset = offsetof(struct boot_file_head, string_pool);
 996}
 997
 998int board_fit_config_name_match(const char *name)
 999{
1000        const char *best_dt_name = get_spl_dt_name();
1001        int ret;
1002
1003#ifdef CONFIG_DEFAULT_DEVICE_TREE
1004        if (best_dt_name == NULL)
1005                best_dt_name = CONFIG_DEFAULT_DEVICE_TREE;
1006#endif
1007
1008        if (best_dt_name == NULL) {
1009                /* No DT name was provided, so accept the first config. */
1010                return 0;
1011        }
1012#ifdef CONFIG_PINE64_DT_SELECTION
1013        if (strstr(best_dt_name, "-pine64-plus")) {
1014                /* Differentiate the Pine A64 boards by their DRAM size. */
1015                if ((gd->ram_size == 512 * 1024 * 1024))
1016                        best_dt_name = "sun50i-a64-pine64";
1017        }
1018#endif
1019#ifdef CONFIG_PINEPHONE_DT_SELECTION
1020        if (strstr(best_dt_name, "-pinephone")) {
1021                /* Differentiate the PinePhone revisions by GPIO inputs. */
1022                prcm_apb0_enable(PRCM_APB0_GATE_PIO);
1023                sunxi_gpio_set_pull(SUNXI_GPL(6), SUNXI_GPIO_PULL_UP);
1024                sunxi_gpio_set_cfgpin(SUNXI_GPL(6), SUNXI_GPIO_INPUT);
1025                udelay(100);
1026
1027                /* PL6 is pulled low by the modem on v1.2. */
1028                if (gpio_get_value(SUNXI_GPL(6)) == 0)
1029                        best_dt_name = "sun50i-a64-pinephone-1.2";
1030                else
1031                        best_dt_name = "sun50i-a64-pinephone-1.1";
1032
1033                sunxi_gpio_set_cfgpin(SUNXI_GPL(6), SUNXI_GPIO_DISABLE);
1034                sunxi_gpio_set_pull(SUNXI_GPL(6), SUNXI_GPIO_PULL_DISABLE);
1035                prcm_apb0_disable(PRCM_APB0_GATE_PIO);
1036        }
1037#endif
1038
1039        ret = strcmp(name, best_dt_name);
1040
1041        /*
1042         * If one of the FIT configurations matches the most accurate DT name,
1043         * update the SPL header to provide that DT name to U-Boot proper.
1044         */
1045        if (ret == 0)
1046                set_spl_dt_name(best_dt_name);
1047
1048        return ret;
1049}
1050#endif
1051