/* * Copyright (c) 2009, Google Inc. * All rights reserved. * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name of Google, Inc. nor the names of its contributors * may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static const uint8_t uart_gsbi_id = GSBI_ID_12; /* Setting this variable to different values defines the * behavior of CE engine: * platform_ce_type = CRYPTO_ENGINE_TYPE_NONE : No CE engine * platform_ce_type = CRYPTO_ENGINE_TYPE_SW : Software CE engine * platform_ce_type = CRYPTO_ENGINE_TYPE_HW : Hardware CE engine * Behavior is determined in the target code. */ static crypto_engine_type platform_ce_type = CRYPTO_ENGINE_TYPE_SW; void keypad_init(void); extern void dmb(void); int target_is_emmc_boot(void); void debug_led_write(char); char debug_led_read(); uint32_t platform_id_read(void); void setup_fpga(void); int pm8901_reset_pwr_off(int reset); int pm8058_reset_pwr_off(int reset); int pm8058_rtc0_alarm_irq_disable(void); static void target_shutdown_for_rtc_alarm(void); void target_init(void) { target_shutdown_for_rtc_alarm(); dprintf(INFO, "target_init()\n"); setup_fpga(); /* Setting Debug LEDs ON */ debug_led_write(0xFF); #if (!ENABLE_NANDWRITE) keys_init(); keypad_init(); #endif /* Display splash screen if enabled */ #if DISPLAY_SPLASH_SCREEN display_init(); dprintf(SPEW, "Diplay initialized\n"); display_image_on_screen(); #endif if (mmc_boot_main(MMC_SLOT, MSM_SDC1_BASE)) { dprintf(CRITICAL, "mmc init failed!"); ASSERT(0); } } unsigned board_machtype(void) { struct smem_board_info_v5 board_info_v5; struct smem_board_info_v6 board_info_v6; unsigned int board_info_len = 0; unsigned smem_status = 0; unsigned format = 0; unsigned id = 0; unsigned hw_platform = 0; unsigned fused_chip = 0; unsigned platform_subtype = 0; static unsigned mach_id = 0xFFFFFFFF; if (mach_id != 0xFFFFFFFF) return mach_id; /* Detect external msm if this is a "fusion" */ smem_status = smem_read_alloc_entry_offset(SMEM_BOARD_INFO_LOCATION, &format, sizeof(format), 0); if (!smem_status) { if (format == 5) { board_info_len = sizeof(board_info_v5); smem_status = smem_read_alloc_entry(SMEM_BOARD_INFO_LOCATION, &board_info_v5, board_info_len); if (!smem_status) { fused_chip = board_info_v5.fused_chip; id = board_info_v5.board_info_v3.hw_platform; } } else if (format == 6) { board_info_len = sizeof(board_info_v6); smem_status = smem_read_alloc_entry(SMEM_BOARD_INFO_LOCATION, &board_info_v6, board_info_len); if (!smem_status) { fused_chip = board_info_v6.fused_chip; id = board_info_v6.board_info_v3.hw_platform; platform_subtype = board_info_v6.platform_subtype; } } } /* Detect SURF v/s FFA v/s Fluid */ switch (id) { case 0x1: hw_platform = HW_PLATFORM_SURF; break; case 0x2: hw_platform = HW_PLATFORM_FFA; break; case 0x3: hw_platform = HW_PLATFORM_FLUID; break; case 0x6: hw_platform = HW_PLATFORM_QT; break; case 0xA: hw_platform = HW_PLATFORM_DRAGON; break; default: /* Writing to Debug LED register and reading back to auto detect SURF and FFA. If we read back, it is SURF */ debug_led_write(0xA5); if ((debug_led_read() & 0xFF) == 0xA5) { debug_led_write(0); hw_platform = HW_PLATFORM_SURF; } else hw_platform = HW_PLATFORM_FFA; }; /* Use platform_subtype or fused_chip information to determine machine id */ if (format >= 6) { switch (platform_subtype) { case HW_PLATFORM_SUBTYPE_CSFB: case HW_PLATFORM_SUBTYPE_SVLTE2A: if (hw_platform == HW_PLATFORM_SURF) mach_id = LINUX_MACHTYPE_8660_CHARM_SURF; else if (hw_platform == HW_PLATFORM_FFA) mach_id = LINUX_MACHTYPE_8660_CHARM_FFA; break; default: if (hw_platform == HW_PLATFORM_SURF) mach_id = LINUX_MACHTYPE_8660_SURF; else if (hw_platform == HW_PLATFORM_FFA) mach_id = LINUX_MACHTYPE_8660_FFA; else if (hw_platform == HW_PLATFORM_FLUID) mach_id = LINUX_MACHTYPE_8660_FLUID; else if (hw_platform == HW_PLATFORM_QT) mach_id = LINUX_MACHTYPE_8660_QT; else if (hw_platform == HW_PLATFORM_DRAGON) mach_id = LINUX_MACHTYPE_8x60_DRAGON; } } else if (format == 5) { switch (fused_chip) { case UNKNOWN: if (hw_platform == HW_PLATFORM_SURF) mach_id = LINUX_MACHTYPE_8660_SURF; else if (hw_platform == HW_PLATFORM_FFA) mach_id = LINUX_MACHTYPE_8660_FFA; else if (hw_platform == HW_PLATFORM_FLUID) mach_id = LINUX_MACHTYPE_8660_FLUID; else if (hw_platform == HW_PLATFORM_QT) mach_id = LINUX_MACHTYPE_8660_QT; else if (hw_platform == HW_PLATFORM_DRAGON) mach_id = LINUX_MACHTYPE_8x60_DRAGON; break; case MDM9200: case MDM9600: if (hw_platform == HW_PLATFORM_SURF) mach_id = LINUX_MACHTYPE_8660_CHARM_SURF; else if (hw_platform == HW_PLATFORM_FFA) mach_id = LINUX_MACHTYPE_8660_CHARM_FFA; break; default: mach_id = LINUX_MACHTYPE_8660_FFA; } } return mach_id; } void shutdown_device() { gpio_config_pshold(); pm8058_reset_pwr_off(0); pm8901_reset_pwr_off(0); writel(0, MSM_PSHOLD_CTL_SU); mdelay(10000); dprintf(CRITICAL, "Shutdown failed\n"); } void reboot_device(unsigned reboot_reason) { /* Reset WDG0 counter */ writel(1, MSM_WDT0_RST); /* Disable WDG0 */ writel(0, MSM_WDT0_EN); /* Set WDG0 bark time */ writel(0x31F3, MSM_WDT0_BT); /* Enable WDG0 */ writel(3, MSM_WDT0_EN); dmb(); /* Enable WDG output */ secure_writel(3, MSM_TCSR_BASE + TCSR_WDOG_CFG); mdelay(10000); dprintf(CRITICAL, "Rebooting failed\n"); return; } unsigned check_reboot_mode(void) { unsigned restart_reason = 0; void *restart_reason_addr = (void *)0x2A05F65C; /* Read reboot reason and scrub it */ restart_reason = readl(restart_reason_addr); writel(0x00, restart_reason_addr); return restart_reason; } void target_battery_charging_enable(unsigned enable, unsigned disconnect) { } void setup_fpga() { writel(0x147, GPIO_CFG133_ADDR); writel(0x144, GPIO_CFG135_ADDR); writel(0x144, GPIO_CFG136_ADDR); writel(0x144, GPIO_CFG137_ADDR); writel(0x144, GPIO_CFG138_ADDR); writel(0x144, GPIO_CFG139_ADDR); writel(0x144, GPIO_CFG140_ADDR); writel(0x144, GPIO_CFG141_ADDR); writel(0x144, GPIO_CFG142_ADDR); writel(0x144, GPIO_CFG143_ADDR); writel(0x144, GPIO_CFG144_ADDR); writel(0x144, GPIO_CFG145_ADDR); writel(0x144, GPIO_CFG146_ADDR); writel(0x144, GPIO_CFG147_ADDR); writel(0x144, GPIO_CFG148_ADDR); writel(0x144, GPIO_CFG149_ADDR); writel(0x144, GPIO_CFG150_ADDR); writel(0x147, GPIO_CFG151_ADDR); writel(0x147, GPIO_CFG152_ADDR); writel(0x147, GPIO_CFG153_ADDR); writel(0x3, GPIO_CFG154_ADDR); writel(0x147, GPIO_CFG155_ADDR); writel(0x147, GPIO_CFG156_ADDR); writel(0x147, GPIO_CFG157_ADDR); writel(0x3, GPIO_CFG158_ADDR); writel(0x00000B31, EBI2_CHIP_SELECT_CFG0); writel(0xA3030020, EBI2_XMEM_CS3_CFG1); } void debug_led_write(char val) { writeb(val, SURF_DEBUG_LED_ADDR); } char debug_led_read() { return readb(SURF_DEBUG_LED_ADDR); } unsigned target_baseband() { struct smem_board_info_v5 board_info_v5; struct smem_board_info_v6 board_info_v6; unsigned int board_info_len = 0; unsigned smem_status = 0; unsigned format = 0; unsigned baseband = BASEBAND_MSM; smem_status = smem_read_alloc_entry_offset(SMEM_BOARD_INFO_LOCATION, &format, sizeof(format), 0); if (!smem_status) { if (format == 5) { board_info_len = sizeof(board_info_v5); smem_status = smem_read_alloc_entry(SMEM_BOARD_INFO_LOCATION, &board_info_v5, board_info_len); if (!smem_status) { /* Check for LTE fused targets or APQ. Default to MSM */ if (board_info_v5.fused_chip == MDM9200) baseband = BASEBAND_CSFB; else if (board_info_v5.fused_chip == MDM9600) baseband = BASEBAND_SVLTE2A; else if (board_info_v5.board_info_v3.msm_id == APQ8060) baseband = BASEBAND_APQ; else baseband = BASEBAND_MSM; } } else if (format >= 6) { board_info_len = sizeof(board_info_v6); smem_status = smem_read_alloc_entry(SMEM_BOARD_INFO_LOCATION, &board_info_v6, board_info_len); if (!smem_status) { /* Check for LTE fused targets or APQ. Default to MSM */ if (board_info_v6.platform_subtype == HW_PLATFORM_SUBTYPE_CSFB) baseband = BASEBAND_CSFB; else if (board_info_v6.platform_subtype == HW_PLATFORM_SUBTYPE_SVLTE2A) baseband = BASEBAND_SVLTE2A; else if (board_info_v6.board_info_v3.msm_id == APQ8060) baseband = BASEBAND_APQ; else baseband = BASEBAND_MSM; } } } return baseband; } crypto_engine_type board_ce_type(void) { struct smem_board_info_v5 board_info_v5; struct smem_board_info_v6 board_info_v6; unsigned int board_info_len = 0; unsigned smem_status = 0; unsigned format = 0; smem_status = smem_read_alloc_entry_offset(SMEM_BOARD_INFO_LOCATION, &format, sizeof(format), 0); if (!smem_status) { if (format == 5) { board_info_len = sizeof(board_info_v5); smem_status = smem_read_alloc_entry(SMEM_BOARD_INFO_LOCATION, &board_info_v5, board_info_len); if (!smem_status) { if ((board_info_v5.board_info_v3.msm_id == APQ8060) || (board_info_v5.board_info_v3.msm_id == MSM8660) || (board_info_v5.board_info_v3.msm_id == MSM8260)) platform_ce_type = CRYPTO_ENGINE_TYPE_HW; } } else if (format >= 6) { board_info_len = sizeof(board_info_v6); smem_status = smem_read_alloc_entry(SMEM_BOARD_INFO_LOCATION, &board_info_v6, board_info_len); if(!smem_status) { if ((board_info_v6.board_info_v3.msm_id == APQ8060) || (board_info_v6.board_info_v3.msm_id == MSM8660) || (board_info_v6.board_info_v3.msm_id == MSM8260)) platform_ce_type = CRYPTO_ENGINE_TYPE_HW; } } } return platform_ce_type; } static unsigned target_check_power_on_reason(void) { unsigned power_on_status = 0; unsigned int status_len = sizeof(power_on_status); unsigned smem_status; smem_status = smem_read_alloc_entry(SMEM_POWER_ON_STATUS_INFO, &power_on_status, status_len); if (smem_status) { dprintf(CRITICAL, "ERROR: unable to read shared memory for power on reason\n"); } dprintf(INFO, "Power on reason %u\n", power_on_status); return power_on_status; } static void target_shutdown_for_rtc_alarm(void) { if (target_check_power_on_reason() == PWR_ON_EVENT_RTC_ALARM) { dprintf(CRITICAL, "Power on due to RTC alarm. Going to shutdown!!\n"); pm8058_rtc0_alarm_irq_disable(); shutdown_device(); } } unsigned target_pause_for_battery_charge(void) { if (target_check_power_on_reason() == PWR_ON_EVENT_WALL_CHG) return 1; return 0; } void target_serialno(unsigned char *buf) { unsigned int serialno; if (target_is_emmc_boot()) { serialno = mmc_get_psn(); snprintf((char *)buf, 13, "%x", serialno); } } void hsusb_gpio_init(void) { uint32_t func; uint32_t pull; uint32_t dir; uint32_t enable; uint32_t drv; /* GPIO 131 and 132 need to be configured for connecting to USB HS PHY */ func = 0; enable = 1; pull = GPIO_NO_PULL; dir = 2; drv = GPIO_2MA; gpio_tlmm_config(131, func, dir, pull, drv, enable); gpio_set(131, dir); func = 0; enable = 1; pull = GPIO_NO_PULL; dir = 1; drv = GPIO_2MA; gpio_tlmm_config(132, func, dir, pull, drv, enable); gpio_set(132, dir); return; } #define USB_CLK 0x00902910 #define USB_PHY_CLK 0x00902E20 #define CLK_RESET_ASSERT 0x1 #define CLK_RESET_DEASSERT 0x0 #define CLK_RESET(x,y) writel((y), (x)); static int msm_otg_xceiv_reset() { CLK_RESET(USB_CLK, CLK_RESET_ASSERT); CLK_RESET(USB_PHY_CLK, CLK_RESET_ASSERT); mdelay(20); CLK_RESET(USB_PHY_CLK, CLK_RESET_DEASSERT); CLK_RESET(USB_CLK, CLK_RESET_DEASSERT); mdelay(20); return 0; } static void target_ulpi_init(void) { unsigned int reg; reg = ulpi_read(0x32); dprintf(INFO, " Value of ulpi read 0x32 is %08x\n", reg); ulpi_write(0x30, 0x32); reg = ulpi_read(0x32); dprintf(INFO, " Value of ulpi read 0x32 after write is %08x\n", reg); reg = ulpi_read(0x36); dprintf(INFO, " Value of ulpi read 0x36 is %08x\n", reg); ulpi_write(reg | 0x2, 0x36); reg = ulpi_read(0x36); dprintf(INFO, " Value of ulpi read 0x36 aafter write is %08x\n", reg); } /* Do target specific usb initialization */ void target_usb_init(void) { hsusb_gpio_init(); msm_otg_xceiv_reset(); target_ulpi_init(); } void target_usb_stop(void) { int val; /* Voting down PLL8 */ val = readl(0x009034C0); val &= ~(1 << 8); writel(val, 0x009034C0); } uint8_t target_uart_gsbi(void) { return uart_gsbi_id; } int emmc_recovery_init(void) { int rc; rc = _emmc_recovery_init(); return rc; }