| /* |
| * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License version 2 and |
| * only version 2 as published by the Free Software Foundation. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| */ |
| |
| #include <common.h> |
| #include <asm/global_data.h> |
| #include <asm/io.h> |
| #include <asm/errno.h> |
| #include <environment.h> |
| #include <fdtdec.h> |
| #include <asm/arch-qca-common/gpio.h> |
| #include <asm/arch-qca-common/uart.h> |
| #include <asm/arch-qca-common/scm.h> |
| #include <asm/arch-qca-common/iomap.h> |
| #include <ipq5018.h> |
| #ifdef CONFIG_QCA_MMC |
| #include <mmc.h> |
| #include <sdhci.h> |
| #endif |
| #ifdef CONFIG_USB_XHCI_IPQ |
| #include <dwc3-uboot.h> |
| #include <usb.h> |
| #endif |
| #ifdef CONFIG_QPIC_NAND |
| #include <asm/arch-qca-common/qpic_nand.h> |
| #endif |
| #ifdef CONFIG_IPQ_BT_SUPPORT |
| #include <malloc.h> |
| #include "bt.h" |
| #include "bt_binary_array.h" |
| #include <linux/compat.h> |
| #endif |
| |
| #define DLOAD_MAGIC_COOKIE 0x10 |
| |
| #define TCSR_SOC_HW_VERSION_REG 0x194D000 |
| |
| ipq_gmac_board_cfg_t gmac_cfg[CONFIG_IPQ_NO_MACS]; |
| |
| DECLARE_GLOBAL_DATA_PTR; |
| |
| #ifdef CONFIG_QCA_MMC |
| struct sdhci_host mmc_host; |
| #endif |
| |
| #ifdef CONFIG_MTD_DEVICE |
| extern int ipq_spi_init(u16); |
| #endif |
| |
| extern void ppe_uniphy_set_forceMode(void); |
| extern void ppe_uniphy_refclk_set(void); |
| |
| unsigned int qpic_frequency = 0, qpic_phase = 0; |
| |
| const char *rsvd_node = "/reserved-memory"; |
| const char *del_node[] = {"uboot", |
| "sbl", |
| NULL}; |
| const add_node_t add_fdt_node[] = {{}}; |
| |
| struct dumpinfo_t dumpinfo_n[] = { |
| /* TZ stores the DDR physical address at which it stores the |
| * APSS regs, UTCM copy dump. We will have the TZ IMEM |
| * IMEM Addr at which the DDR physical address is stored as |
| * the start |
| * -------------------- |
| * | DDR phy (start) | ----> ------------------------ |
| * -------------------- | APSS regsave (8k) | |
| * ------------------------ |
| * | | |
| * | UTCM copy | |
| * | (192k) | |
| * | | |
| * ------------------------ |
| * | | |
| * | BTRAM Copy | |
| * | (352k) | |
| * | | |
| * ------------------------ |
| */ |
| { "EBICS0.BIN", 0x40000000, 0x10000000, 0 }, |
| /* |
| * The below 3 config enable compress crash dump support. |
| * the RAM region will be split in 3 section and collect based on the |
| * config as given below. NOT SUPPORT IN TINY_NOR profile. |
| * Note : EBICS2.BIN start and size varies dynamically based on RAM size. |
| * basically it's seconds half of ram region. |
| */ |
| #ifndef CONFIG_IPQ_TINY |
| { "EBICS10.BIN", 0x79C00000, 0x6400000, 0, 0, 0, 0, 1 }, |
| { "EBICS9.BIN", 0x73800000, 0x6400000, 0, 0, 0, 0, 1 }, |
| { "EBICS8.BIN", 0x6D400000, 0x6400000, 0, 0, 0, 0, 1 }, |
| { "EBICS7.BIN", 0x67000000, 0x6400000, 0, 0, 0, 0, 1 }, |
| { "EBICS6.BIN", 0x60C00000, 0x6400000, 0, 0, 0, 0, 1 }, |
| { "EBICS5.BIN", 0x5A800000, 0x6400000, 0, 0, 0, 0, 1 }, |
| { "EBICS4.BIN", 0x54400000, 0x6400000, 0, 0, 0, 0, 1 }, |
| { "EBICS3.BIN", 0x4E000000, 0x6400000, 0, 0, 0, 0, 1 }, |
| { "EBICS2.BIN", CONFIG_SMEM_END_ADDR, (0x4E000000 - CONFIG_SMEM_END_ADDR), 0, 0, 0, 0, 1 }, |
| { "EBICS1.BIN", (0x40000000 + (CONFIG_QCA_UBOOT_OFFSET / 2)), (CONFIG_QCA_UBOOT_OFFSET / 2), 0, 0, 0, 0, 1 }, |
| { "EBICS0.BIN", 0x40000000, (CONFIG_QCA_UBOOT_OFFSET / 2), 0, 0, 0, 0, 1 }, |
| #endif |
| { "IMEM.BIN", 0x08600000, 0x00001000, 0 }, |
| { "NSSUTCM.BIN", 0x08600658, 0x00030000, 0, 1, 0x2000 }, |
| { "BTRAM.BIN", 0x08600658, 0x00058000, 0, 1, 0x00032000 }, |
| { "UNAME.BIN", 0, 0, 0, 0, 0, MINIMAL_DUMP }, |
| { "CPU_INFO.BIN", 0, 0, 0, 0, 0, MINIMAL_DUMP }, |
| { "DMESG.BIN", 0, 0, 0, 0, 0, MINIMAL_DUMP }, |
| { "PT.BIN", 0, 0, 0, 0, 0, MINIMAL_DUMP }, |
| { "WLAN_MOD.BIN", 0, 0, 0, 0, 0, MINIMAL_DUMP }, |
| }; |
| int dump_entries_n = ARRAY_SIZE(dumpinfo_n); |
| |
| struct dumpinfo_t dumpinfo_s[] = { |
| { "EBICS_S0.BIN", 0x40000000, 0xAC00000, 0 }, |
| { "EBICS_S1.BIN", CONFIG_TZ_END_ADDR, 0x10000000, 0 }, |
| #ifndef CONFIG_IPQ_TINY |
| { "EBICS10.BIN", 0x79C00000, 0x6400000, 0, 0, 0, 0, 1 }, |
| { "EBICS9.BIN", 0x73800000, 0x6400000, 0, 0, 0, 0, 1 }, |
| { "EBICS8.BIN", 0x6D400000, 0x6400000, 0, 0, 0, 0, 1 }, |
| { "EBICS7.BIN", 0x67000000, 0x6400000, 0, 0, 0, 0, 1 }, |
| { "EBICS6.BIN", 0x60C00000, 0x6400000, 0, 0, 0, 0, 1 }, |
| { "EBICS5.BIN", 0x5A800000, 0x6400000, 0, 0, 0, 0, 1 }, |
| { "EBICS4.BIN", 0x54400000, 0x6400000, 0, 0, 0, 0, 1 }, |
| { "EBICS3.BIN", 0x4E000000, 0x6400000, 0, 0, 0, 0, 1 }, |
| { "EBICS2.BIN", CONFIG_TZ_END_ADDR, (0x4E000000 - CONFIG_TZ_END_ADDR), 0, 0, 0, 0, 1 }, |
| { "EBICS1.BIN", (0x40000000 + (CONFIG_QCA_UBOOT_OFFSET / 2)), (CONFIG_QCA_UBOOT_OFFSET / 2), 0, 0, 0, 0, 1 }, |
| { "EBICS0.BIN", 0x40000000, (CONFIG_QCA_UBOOT_OFFSET / 2), 0, 0, 0, 0, 1 }, |
| #endif |
| { "IMEM.BIN", 0x08600000, 0x00001000, 0 }, |
| { "NSSUTCM.BIN", 0x08600658, 0x00030000, 0, 1, 0x2000 }, |
| { "BTRAM.BIN", 0x08600658, 0x00058000, 0, 1, 0x00032000 }, |
| { "UNAME.BIN", 0, 0, 0, 0, 0, MINIMAL_DUMP }, |
| { "CPU_INFO.BIN", 0, 0, 0, 0, 0, MINIMAL_DUMP }, |
| { "DMESG.BIN", 0, 0, 0, 0, 0, MINIMAL_DUMP }, |
| { "PT.BIN", 0, 0, 0, 0, 0, MINIMAL_DUMP }, |
| { "WLAN_MOD.BIN", 0, 0, 0, 0, 0, MINIMAL_DUMP }, |
| }; |
| int dump_entries_s = ARRAY_SIZE(dumpinfo_s); |
| u32 *tz_wonce = (u32 *)CONFIG_IPQ5018_TZ_WONCE_4_ADDR; |
| |
| void uart1_configure_mux(void) |
| { |
| unsigned long cfg_rcgr; |
| |
| cfg_rcgr = readl(GCC_BLSP1_UART1_APPS_CFG_RCGR); |
| /* Clear mode, src sel, src div */ |
| cfg_rcgr &= ~(GCC_UART_CFG_RCGR_MODE_MASK | |
| GCC_UART_CFG_RCGR_SRCSEL_MASK | |
| GCC_UART_CFG_RCGR_SRCDIV_MASK); |
| |
| cfg_rcgr |= ((UART1_RCGR_SRC_SEL << GCC_UART_CFG_RCGR_SRCSEL_SHIFT) |
| & GCC_UART_CFG_RCGR_SRCSEL_MASK); |
| |
| cfg_rcgr |= ((UART1_RCGR_SRC_DIV << GCC_UART_CFG_RCGR_SRCDIV_SHIFT) |
| & GCC_UART_CFG_RCGR_SRCDIV_MASK); |
| |
| cfg_rcgr |= ((UART1_RCGR_MODE << GCC_UART_CFG_RCGR_MODE_SHIFT) |
| & GCC_UART_CFG_RCGR_MODE_MASK); |
| |
| writel(cfg_rcgr, GCC_BLSP1_UART1_APPS_CFG_RCGR); |
| } |
| |
| void uart1_set_rate_mnd(unsigned int m, |
| unsigned int n, unsigned int two_d) |
| { |
| writel(m, GCC_BLSP1_UART1_APPS_M); |
| writel(n, GCC_BLSP1_UART1_APPS_N); |
| writel(two_d, GCC_BLSP1_UART1_APPS_D); |
| } |
| |
| void reset_board(void) |
| { |
| run_command("reset", 0); |
| } |
| |
| void uart1_toggle_clock(void) |
| { |
| unsigned long cbcr_val; |
| |
| cbcr_val = readl(GCC_BLSP1_UART1_APPS_CBCR); |
| cbcr_val |= UART1_CBCR_CLK_ENABLE; |
| writel(cbcr_val, GCC_BLSP1_UART1_APPS_CBCR); |
| } |
| |
| int uart1_trigger_update(void) |
| { |
| unsigned long cmd_rcgr; |
| int timeout = 0; |
| |
| cmd_rcgr = readl(GCC_BLSP1_UART1_APPS_CMD_RCGR); |
| cmd_rcgr |= UART1_CMD_RCGR_UPDATE | UART1_CMD_RCGR_ROOT_EN; |
| writel(cmd_rcgr, GCC_BLSP1_UART1_APPS_CMD_RCGR); |
| |
| while (readl(GCC_BLSP1_UART1_APPS_CMD_RCGR) & UART1_CMD_RCGR_UPDATE) { |
| if (timeout++ >= CLOCK_UPDATE_TIMEOUT_US) { |
| printf("Timeout waiting for UART1 clock update\n"); |
| return -ETIMEDOUT; |
| udelay(1); |
| } |
| } |
| uart1_toggle_clock(); |
| return 0; |
| } |
| |
| int uart1_clock_config(struct ipq_serial_platdata *plat) |
| { |
| |
| uart1_configure_mux(); |
| uart1_set_rate_mnd(plat->m_value, |
| plat->n_value, |
| plat->d_value); |
| return uart1_trigger_update(); |
| } |
| |
| void qca_serial_init(struct ipq_serial_platdata *plat) |
| { |
| int ret; |
| |
| if (plat->gpio_node < 0) { |
| printf("serial_init: unable to find gpio node \n"); |
| return; |
| } |
| qca_gpio_init(plat->gpio_node); |
| ret = uart1_clock_config(plat); |
| if (ret) |
| printf("UART clock config failed %d \n", ret); |
| } |
| |
| /* |
| * Set the uuid in bootargs variable for mounting rootfilesystem |
| */ |
| #ifdef CONFIG_QCA_MMC |
| int set_uuid_bootargs(char *boot_args, char *part_name, int buflen, bool gpt_flag) |
| { |
| int ret, len; |
| block_dev_desc_t *blk_dev; |
| disk_partition_t disk_info; |
| |
| blk_dev = mmc_get_dev(mmc_host.dev_num); |
| if (!blk_dev) { |
| printf("Invalid block device name\n"); |
| return -EINVAL; |
| } |
| |
| if (buflen <= 0 || buflen > MAX_BOOT_ARGS_SIZE) |
| return -EINVAL; |
| |
| #ifdef CONFIG_PARTITION_UUIDS |
| ret = get_partition_info_efi_by_name(blk_dev, |
| part_name, &disk_info); |
| if (ret) { |
| printf("bootipq: unsupported partition name %s\n",part_name); |
| return -EINVAL; |
| } |
| if ((len = strlcpy(boot_args, "root=PARTUUID=", buflen)) >= buflen) |
| return -EINVAL; |
| #else |
| if ((len = strlcpy(boot_args, "rootfsname=", buflen)) >= buflen) |
| return -EINVAL; |
| #endif |
| boot_args += len; |
| buflen -= len; |
| |
| #ifdef CONFIG_PARTITION_UUIDS |
| if ((len = strlcpy(boot_args, disk_info.uuid, buflen)) >= buflen) |
| return -EINVAL; |
| #else |
| if ((len = strlcpy(boot_args, part_name, buflen)) >= buflen) |
| return -EINVAL; |
| #endif |
| boot_args += len; |
| buflen -= len; |
| |
| if (gpt_flag && strlcpy(boot_args, " gpt", buflen) >= buflen) |
| return -EINVAL; |
| |
| return 0; |
| } |
| #else |
| int set_uuid_bootargs(char *boot_args, char *part_name, int buflen, bool gpt_flag) |
| { |
| return 0; |
| } |
| #endif |
| |
| #ifdef CONFIG_QCA_MMC |
| void emmc_clock_config(void) |
| { |
| /* Enable root clock generator */ |
| writel(readl(GCC_SDCC1_APPS_CBCR)|0x1, GCC_SDCC1_APPS_CBCR); |
| /* Add 10us delay for CLK_OFF to get cleared */ |
| udelay(10); |
| writel(readl(GCC_SDCC1_AHB_CBCR)|0x1, GCC_SDCC1_AHB_CBCR); |
| /* PLL0 - 192Mhz */ |
| writel(0x20B, GCC_SDCC1_APPS_CFG_RCGR); |
| /* Delay for clock operation complete */ |
| udelay(10); |
| writel(0x1, GCC_SDCC1_APPS_M); |
| /* check this M, N D value while debugging |
| * because as per clock tool the actual M, N, D |
| * values are M=1, N=FA, D=F9 |
| */ |
| writel(0xFC, GCC_SDCC1_APPS_N); |
| writel(0xFD, GCC_SDCC1_APPS_D); |
| /* Delay for clock operation complete */ |
| udelay(10); |
| /* Update APPS_CMD_RCGR to reflect source selection */ |
| writel(readl(GCC_SDCC1_APPS_CMD_RCGR)|0x1, GCC_SDCC1_APPS_CMD_RCGR); |
| /* Add 10us delay for clock update to complete */ |
| udelay(10); |
| } |
| |
| void mmc_iopad_config(struct sdhci_host *host) |
| { |
| u32 val; |
| val = sdhci_readb(host, SDHCI_VENDOR_IOPAD); |
| /*set bit 15 & 16*/ |
| val |= 0x18000; |
| writel(val, host->ioaddr + SDHCI_VENDOR_IOPAD); |
| } |
| |
| void sdhci_bus_pwr_off(struct sdhci_host *host) |
| { |
| u32 val; |
| |
| val = sdhci_readb(host, SDHCI_HOST_CONTROL); |
| sdhci_writeb(host,(val & (~SDHCI_POWER_ON)), SDHCI_POWER_CONTROL); |
| } |
| |
| __weak void board_mmc_deinit(void) |
| { |
| /*since we do not have misc register in ipq5018 |
| * so simply return from this function |
| */ |
| return; |
| } |
| |
| void emmc_clock_reset(void) |
| { |
| writel(0x1, GCC_SDCC1_BCR); |
| udelay(10); |
| writel(0x0, GCC_SDCC1_BCR); |
| } |
| |
| int board_mmc_init(bd_t *bis) |
| { |
| int node, gpio_node; |
| int ret = 0; |
| qca_smem_flash_info_t *sfi = &qca_smem_flash_info; |
| node = fdt_path_offset(gd->fdt_blob, "mmc"); |
| if (node < 0) { |
| printf("sdhci: Node Not found, skipping initialization\n"); |
| return -1; |
| } |
| |
| gpio_node = fdt_subnode_offset(gd->fdt_blob, node, "mmc_gpio"); |
| qca_gpio_init(gpio_node); |
| |
| mmc_host.ioaddr = (void *)MSM_SDC1_SDHCI_BASE; |
| mmc_host.voltages = MMC_VDD_165_195; |
| mmc_host.version = SDHCI_SPEC_300; |
| mmc_host.cfg.part_type = PART_TYPE_EFI; |
| mmc_host.quirks = SDHCI_QUIRK_BROKEN_VOLTAGE; |
| |
| emmc_clock_reset(); |
| udelay(10); |
| emmc_clock_config(); |
| |
| if (add_sdhci(&mmc_host, 200000000, 400000)) { |
| printf("add_sdhci fail!\n"); |
| return -1; |
| } |
| |
| if (!ret && sfi->flash_type == SMEM_BOOT_MMC_FLASH) { |
| ret = board_mmc_env_init(mmc_host); |
| } |
| |
| return ret; |
| } |
| #else |
| int board_mmc_init(bd_t *bis) |
| { |
| return 0; |
| } |
| #endif |
| |
| __weak int ipq_get_tz_version(char *version_name, int buf_size) |
| { |
| return 1; |
| } |
| |
| int apps_iscrashed(void) |
| { |
| u32 *dmagic = (u32 *)CONFIG_IPQ5018_DMAGIC_ADDR; |
| |
| if (*dmagic == DLOAD_MAGIC_COOKIE) |
| return 1; |
| |
| return 0; |
| } |
| |
| static void __fixup_usb_device_mode(void *blob) |
| { |
| parse_fdt_fixup("/soc/usb3@8A00000/dwc3@8A00000%dr_mode%?peripheral", blob); |
| parse_fdt_fixup("/soc/usb3@8A00000/dwc3@8A00000%maximum-speed%?high-speed", blob); |
| } |
| |
| static void fdt_fixup_diag_gadget(void *blob) |
| { |
| __fixup_usb_device_mode(blob); |
| parse_fdt_fixup("/soc/qcom,gadget_diag@0%status%?ok", blob); |
| } |
| |
| void ipq_fdt_fixup_usb_device_mode(void *blob) |
| { |
| const char *usb_cfg; |
| |
| usb_cfg = getenv("usb_mode"); |
| if (!usb_cfg) |
| return; |
| |
| if (!strncmp(usb_cfg, "peripheral", sizeof("peripheral"))) |
| __fixup_usb_device_mode(blob); |
| else if (!strncmp(usb_cfg, "diag_gadget", sizeof("diag_gadget"))) |
| fdt_fixup_diag_gadget(blob); |
| else |
| printf("%s: invalid param for usb_mode\n", __func__); |
| } |
| |
| void ipq_fdt_fixup_socinfo(void *blob) |
| { |
| uint32_t cpu_type; |
| uint32_t soc_version, soc_version_major, soc_version_minor; |
| int nodeoff, ret; |
| |
| nodeoff = fdt_path_offset(blob, "/"); |
| |
| if (nodeoff < 0) { |
| printf("ipq: fdt fixup cannot find root node\n"); |
| return; |
| } |
| |
| ret = ipq_smem_get_socinfo_cpu_type(&cpu_type); |
| if (!ret) { |
| ret = fdt_setprop(blob, nodeoff, "cpu_type", |
| &cpu_type, sizeof(cpu_type)); |
| if (ret) |
| printf("%s: cannot set cpu type %d\n", __func__, ret); |
| } else { |
| printf("%s: cannot get socinfo\n", __func__); |
| } |
| |
| ret = ipq_smem_get_socinfo_version((uint32_t *)&soc_version); |
| if (!ret) { |
| soc_version_major = SOCINFO_VERSION_MAJOR(soc_version); |
| soc_version_minor = SOCINFO_VERSION_MINOR(soc_version); |
| |
| ret = fdt_setprop(blob, nodeoff, "soc_version_major", |
| &soc_version_major, |
| sizeof(soc_version_major)); |
| if (ret) |
| printf("%s: cannot set soc_version_major %d\n", |
| __func__, soc_version_major); |
| |
| ret = fdt_setprop(blob, nodeoff, "soc_version_minor", |
| &soc_version_minor, |
| sizeof(soc_version_minor)); |
| if (ret) |
| printf("%s: cannot set soc_version_minor %d\n", |
| __func__, soc_version_minor); |
| } else { |
| printf("%s: cannot get soc version\n", __func__); |
| } |
| return; |
| } |
| |
| void fdt_fixup_auto_restart(void *blob) |
| { |
| const char *paniconwcssfatal; |
| |
| paniconwcssfatal = getenv("paniconwcssfatal"); |
| |
| if (!paniconwcssfatal) |
| return; |
| |
| if (strncmp(paniconwcssfatal, "1", sizeof("1"))) { |
| printf("fixup_auto_restart: invalid variable 'paniconwcssfatal'"); |
| } else { |
| parse_fdt_fixup("/soc/q6v5_wcss@CD00000%delete%?qca,auto-restart", blob); |
| } |
| return; |
| } |
| |
| #ifdef CONFIG_IPQ_BT_SUPPORT |
| int bt_running; |
| |
| unsigned char hci_reset[] = |
| {0x01, 0x03, 0x0c, 0x00}; |
| |
| unsigned char adv_data[] = |
| {0x01, 0X08, 0X20, 0X20, 0X1F, 0X0A, 0X09, 0X71, |
| 0X75, 0X61, 0X6c, 0X63, 0X6f, 0X6d, 0X6d, 0X00, |
| 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, |
| 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, |
| 0X00, 0X00, 0X00, 0X00}; |
| |
| unsigned char set_interval[] = |
| {0X01, 0X06, 0X20, 0X0F, 0X20, 0X00, 0X20, 0X00, |
| 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, |
| 0X00, 0X07, 0X00}; |
| |
| unsigned char start_beacon[] = |
| {0x01, 0x0A, 0x20, 0x01, 0x01}; |
| |
| struct hci_cmd{ |
| unsigned char* data; |
| unsigned int len; |
| }; |
| |
| struct hci_cmd hci_cmds[] = { |
| { hci_reset, sizeof(hci_reset) }, |
| { adv_data, sizeof(adv_data) }, |
| { set_interval, sizeof(set_interval) }, |
| { start_beacon, sizeof(start_beacon) }, |
| }; |
| |
| int wait_for_bt_event(struct bt_descriptor *btDesc, u8 bt_wait) |
| { |
| int val, timeout = 0; |
| |
| do{ |
| udelay(10); |
| bt_ipc_worker(btDesc); |
| |
| if (bt_wait == BT_WAIT_FOR_START) |
| val = !atomic_read(&btDesc->state); |
| else |
| val = atomic_read(&btDesc->tx_in_progress); |
| |
| if (timeout++ >= BT_TIMEOUT_US/10) { |
| printf(" %s timed out \n", __func__); |
| return -ETIMEDOUT; |
| } |
| |
| } while (val); |
| |
| return 0; |
| } |
| |
| static int initialize_nvm(struct bt_descriptor *btDesc, |
| void *fileaddr, u32 filesize) |
| { |
| unsigned char *buffer = fileaddr; |
| int bytes_read = 0, bytes_consumed = 0, ret; |
| HCI_Packet_t *hci_packet = NULL; |
| |
| while(bytes_consumed < filesize ) |
| { |
| bytes_read = (filesize - bytes_consumed) > NVM_SEGMENT_SIZE ? |
| NVM_SEGMENT_SIZE : filesize - bytes_consumed; |
| /* Constructing a HCI Packet to write NVM Segments to BTSS */ |
| hci_packet = (HCI_Packet_t*)malloc(sizeof(HCI_Packet_t) + |
| NVM_SEGMENT_SIZE); |
| |
| if(!hci_packet) |
| { |
| printf("Cannot allocate memory to HCI Packet \n"); |
| return -ENOMEM; |
| } |
| |
| /* Initializing HCI Packet Header */ |
| hci_packet->HCIPacketType = ptHCICommandPacket; |
| |
| /* Populating TLV Request Packet in HCI */ |
| LE_UNALIGNED(&(hci_packet->HCIPayload.opcode), TLV_REQ_OPCODE); |
| LE_UNALIGNED(&(hci_packet->HCIPayload.parameter_total_length), |
| (bytes_read + DATA_REMAINING_LENGTH)); |
| hci_packet->HCIPayload.command_request = TLV_COMMAND_REQUEST; |
| hci_packet->HCIPayload.tlv_segment_length = bytes_read; |
| memcpy(hci_packet->HCIPayload.tlv_segment_data, buffer, |
| bytes_read); |
| |
| bt_ipc_sendmsg(btDesc, (u8*)hci_packet, |
| sizeof(HCI_Packet_t) + bytes_read); |
| |
| free(hci_packet); |
| bytes_consumed += bytes_read; |
| buffer = fileaddr + bytes_consumed; |
| |
| ret = wait_for_bt_event(btDesc, BT_WAIT_FOR_TX_COMPLETE); |
| if(ret || *((u8 *)btDesc->buf + TLV_RESPONSE_STATUS_INDEX) != 0) |
| { |
| printf( "\n NVM download failed\n"); |
| if (!ret) { |
| kfree(btDesc->buf); |
| btDesc->buf = NULL; |
| } |
| return -EINVAL; |
| } |
| kfree(btDesc->buf); |
| btDesc->buf = NULL; |
| } |
| |
| printf("NVM download successful \n"); |
| bt_ipc_worker(btDesc); |
| return 0; |
| } |
| |
| int send_bt_hci_cmds(struct bt_descriptor *btDesc) |
| { |
| int ret, i; |
| int count = sizeof hci_cmds/ sizeof(struct hci_cmd); |
| |
| for (i = 0; i < count; i++) { |
| bt_ipc_sendmsg(btDesc, hci_cmds[i].data, hci_cmds[i].len); |
| |
| ret = wait_for_bt_event(btDesc, BT_WAIT_FOR_TX_COMPLETE); |
| if (ret) |
| return ret; |
| |
| /*btDesc->buf will have response data with length btDesc->len*/ |
| kfree(btDesc->buf); |
| btDesc->buf = NULL; |
| } |
| return 0; |
| } |
| |
| int bt_init(void) |
| { |
| struct bt_descriptor *btDesc; |
| int ret; |
| |
| btDesc = kzalloc(sizeof(*btDesc), GFP_KERNEL); |
| if (!btDesc) |
| return -ENOMEM; |
| |
| bt_ipc_init(btDesc); |
| |
| enable_btss_lpo_clk(); |
| ret = qti_scm_pas_init_image(PAS_ID, (u32)bt_fw_patchmdt); |
| if (ret) { |
| printf("patch auth failed\n"); |
| return ret; |
| } |
| |
| printf("patch authenticated successfully\n"); |
| |
| memcpy((void*)BT_RAM_PATCH, (void*)bt_fw_patchb02, |
| sizeof bt_fw_patchb02); |
| |
| ret = qti_pas_and_auth_reset(PAS_ID); |
| |
| if (ret) { |
| printf("BT out of reset failed\n"); |
| return ret; |
| } |
| |
| ret = wait_for_bt_event(btDesc, BT_WAIT_FOR_START); |
| if (ret) |
| return ret; |
| |
| ret = initialize_nvm(btDesc, (void*)mpnv10bin, sizeof mpnv10bin); |
| if (ret) |
| return ret; |
| |
| ret = wait_for_bt_event(btDesc, BT_WAIT_FOR_START); |
| if (ret) |
| return ret; |
| |
| send_bt_hci_cmds(btDesc); |
| |
| bt_running = 1; |
| return 0; |
| } |
| |
| void fdt_fixup_bt_running(void *blob) |
| { |
| if (bt_running) { |
| parse_fdt_fixup("/soc/bt@7000000%qcom,bt-running%1", blob); |
| } |
| } |
| #endif |
| |
| void reset_crashdump(void) |
| { |
| unsigned int ret = 0; |
| qca_scm_sdi(); |
| ret = qca_scm_dload(CLEAR_MAGIC); |
| if (ret) |
| printf ("Error in reseting the Magic cookie\n"); |
| return; |
| } |
| |
| void psci_sys_reset(void) |
| { |
| __invoke_psci_fn_smc(0x84000009, 0, 0, 0); |
| } |
| |
| void qti_scm_pshold(void) |
| { |
| int ret; |
| |
| ret = scm_call(SCM_SVC_BOOT, SCM_CMD_TZ_PSHOLD, NULL, 0, NULL, 0); |
| |
| if (ret != 0) |
| writel(0, GCNT_PSHOLD); |
| } |
| |
| void reset_cpu(unsigned long a) |
| { |
| reset_crashdump(); |
| if (is_scm_armv8()) { |
| psci_sys_reset(); |
| } else { |
| qti_scm_pshold(); |
| } |
| while(1); |
| } |
| |
| #ifdef CONFIG_QPIC_NAND |
| void qpic_set_clk_rate(unsigned int clk_rate, int blk_type, int req_clk_src_type) |
| { |
| switch (blk_type) { |
| case QPIC_IO_MACRO_CLK: |
| /* select the clk source for IO_PAD_MACRO |
| * clk source wil be either XO = 24MHz. or GPLL0 = 800MHz. |
| */ |
| if (req_clk_src_type == XO_CLK_SRC) { |
| /* default XO clock will enabled |
| * i.e XO clock = 24MHz. |
| * so div value will 0. |
| * Input clock to IO_MACRO will be divided by 4 by default |
| * by hardware and then taht clock will be go on bus. |
| * i.e 24/4MHz = 6MHz i.e 6MHz will go onto the bus. |
| */ |
| writel(0x0, GCC_QPIC_IO_MACRO_CFG_RCGR); |
| |
| } else if (req_clk_src_type == GPLL0_CLK_SRC) { |
| /* selct GPLL0 clock source 800MHz |
| * so 800/4 = 200MHz. |
| * Input clock to IO_MACRO will be divided by 4 by default |
| * by hardware and then that clock will be go on bus. |
| * i.e 200/4MHz = 50MHz i.e 50MHz will go onto the bus. |
| */ |
| if (clk_rate == IO_MACRO_CLK_320_MHZ) |
| writel(0x104, GCC_QPIC_IO_MACRO_CFG_RCGR); |
| else if (clk_rate == IO_MACRO_CLK_266_MHZ) |
| writel(0x105, GCC_QPIC_IO_MACRO_CFG_RCGR); |
| else if (clk_rate == IO_MACRO_CLK_228_MHZ) |
| writel(0x106, GCC_QPIC_IO_MACRO_CFG_RCGR); |
| else if (clk_rate == IO_MACRO_CLK_100_MHZ) |
| writel(0x10F, GCC_QPIC_IO_MACRO_CFG_RCGR); |
| else if (clk_rate == IO_MACRO_CLK_200_MHZ) |
| writel(0x107, GCC_QPIC_IO_MACRO_CFG_RCGR); |
| |
| } else { |
| printf("wrong clk src selection requested.\n"); |
| } |
| |
| /* Enablle update bit to update the new configuration */ |
| writel((UPDATE_EN | readl(GCC_QPIC_IO_MACRO_CMD_RCGR)), |
| GCC_QPIC_IO_MACRO_CMD_RCGR); |
| |
| /* Enable the QPIC_IO_MACRO_CLK */ |
| writel(0x1, GCC_QPIC_IO_MACRO_CBCR); |
| |
| break; |
| case QPIC_CORE_CLK: |
| /* To DO if needed for QPIC core clock setting */ |
| break; |
| default: |
| printf("wrong qpic block type\n"); |
| break; |
| } |
| } |
| #endif |
| |
| void board_nand_init(void) |
| { |
| #ifdef CONFIG_QPIC_SERIAL |
| /* check for nand node in dts |
| * if nand node in dts is disabled then |
| * simply return from here without |
| * initializing |
| */ |
| int node; |
| node = fdt_path_offset(gd->fdt_blob, "/nand-controller"); |
| if (!fdtdec_get_is_enabled(gd->fdt_blob, node)) { |
| printf("QPIC: disabled, skipping initialization\n"); |
| } else { |
| qpic_nand_init(NULL); |
| } |
| #endif |
| |
| #ifdef CONFIG_IPQ_BT_SUPPORT |
| bt_init(); |
| #endif |
| #ifdef CONFIG_QCA_SPI |
| int gpio_node; |
| gpio_node = fdt_path_offset(gd->fdt_blob, "/spi/spi_gpio"); |
| if (gpio_node >= 0) { |
| qca_gpio_init(gpio_node); |
| #ifdef CONFIG_MTD_DEVICE |
| ipq_spi_init(CONFIG_IPQ_SPI_NOR_INFO_IDX); |
| #endif |
| } |
| #endif |
| } |
| |
| void enable_caches(void) |
| { |
| qca_smem_flash_info_t *sfi = &qca_smem_flash_info; |
| smem_get_boot_flash(&sfi->flash_type, |
| &sfi->flash_index, |
| &sfi->flash_chip_select, |
| &sfi->flash_block_size, |
| &sfi->flash_density); |
| icache_enable(); |
| /*Skips dcache_enable during JTAG recovery */ |
| if (sfi->flash_type) |
| dcache_enable(); |
| } |
| |
| void disable_caches(void) |
| { |
| icache_disable(); |
| dcache_disable(); |
| } |
| |
| unsigned long timer_read_counter(void) |
| { |
| return 0; |
| } |
| |
| static void set_ext_mdio_gpio(int node) |
| { |
| unsigned int mdio_gpio[2] = {0}; |
| int status = -1; |
| unsigned int *mdio_gpio_base; |
| |
| status = fdtdec_get_int_array(gd->fdt_blob, |
| node, |
| "ext_mdio_gpio", |
| mdio_gpio, |
| 2); |
| if (status >= 0) { |
| /* mdc */ |
| mdio_gpio_base = |
| (unsigned int *)GPIO_CONFIG_ADDR(mdio_gpio[0]); |
| writel(0x7, mdio_gpio_base); |
| /* mdio */ |
| mdio_gpio_base = |
| (unsigned int *)GPIO_CONFIG_ADDR(mdio_gpio[1]); |
| writel(0x7, mdio_gpio_base); |
| } |
| } |
| |
| static void reset_napa_phy_gpio(int gpio) |
| { |
| unsigned int *napa_gpio_base; |
| |
| napa_gpio_base = (unsigned int *)GPIO_CONFIG_ADDR(gpio); |
| writel(0x203, napa_gpio_base); |
| writel(0x0, GPIO_IN_OUT_ADDR(gpio)); |
| mdelay(500); |
| writel(0x2, GPIO_IN_OUT_ADDR(gpio)); |
| } |
| |
| static void reset_8033_phy_gpio(int gpio) |
| { |
| unsigned int *phy_8033_gpio_base; |
| |
| ppe_uniphy_refclk_set(); |
| phy_8033_gpio_base = (unsigned int *)GPIO_CONFIG_ADDR(gpio); |
| writel(0x2C1, phy_8033_gpio_base); |
| writel(0x0, GPIO_IN_OUT_ADDR(gpio)); |
| mdelay(500); |
| writel(0x2, GPIO_IN_OUT_ADDR(gpio)); |
| } |
| |
| static void reset_s17c_switch_gpio(int gpio) |
| { |
| unsigned int *switch_gpio_base = |
| (unsigned int *)GPIO_CONFIG_ADDR(gpio); |
| /* |
| * Set ref clock 25MHZ and enable Force mode |
| */ |
| ppe_uniphy_refclk_set(); |
| ppe_uniphy_set_forceMode(); |
| |
| writel(0x203, switch_gpio_base); |
| writel(0x0, GPIO_IN_OUT_ADDR(gpio)); |
| mdelay(500); |
| writel(0x2, GPIO_IN_OUT_ADDR(gpio)); |
| } |
| |
| static void cmn_blk_clk_set(void) |
| { |
| /* GMN block */ |
| writel(0x1, GCC_CMN_BLK_AHB_CBCR); |
| mdelay(20); |
| writel(0x1, GCC_CMN_BLK_SYS_CBCR); |
| mdelay(20); |
| } |
| |
| static void uniphy_clk_set(void) |
| { |
| writel(0x1, GCC_UNIPHY_AHB_CBCR); |
| mdelay(20); |
| writel(0x1, GCC_UNIPHY_SYS_CBCR); |
| mdelay(20); |
| writel(0x1, GCC_UNIPHY_RX_CBCR); |
| mdelay(20); |
| writel(0x1, GCC_UNIPHY_TX_CBCR); |
| mdelay(20); |
| |
| } |
| |
| static void gephy_uniphy_clock_disable(void) |
| { |
| u32 reg_val = 0; |
| |
| reg_val = readl(GCC_GEPHY_RX_CBCR); |
| reg_val &= ~GCC_CBCR_CLK_ENABLE; |
| writel(reg_val, GCC_GEPHY_RX_CBCR); |
| mdelay(20); |
| |
| reg_val = readl(GCC_GEPHY_TX_CBCR); |
| reg_val &= ~GCC_CBCR_CLK_ENABLE; |
| writel(reg_val, GCC_GEPHY_TX_CBCR); |
| mdelay(20); |
| |
| reg_val = readl(GCC_UNIPHY_RX_CBCR); |
| reg_val &= ~GCC_CBCR_CLK_ENABLE; |
| writel(reg_val, GCC_UNIPHY_RX_CBCR); |
| mdelay(20); |
| |
| reg_val = readl(GCC_UNIPHY_TX_CBCR); |
| reg_val &= ~GCC_CBCR_CLK_ENABLE; |
| writel(reg_val, GCC_UNIPHY_TX_CBCR); |
| mdelay(20); |
| |
| } |
| |
| static void gmac_clock_disable(void) |
| { |
| u32 reg_val = 0; |
| |
| reg_val = readl(GCC_GMAC0_RX_CBCR); |
| reg_val &= ~GCC_CBCR_CLK_ENABLE; |
| writel(reg_val, GCC_GMAC0_RX_CBCR); |
| mdelay(20); |
| |
| reg_val = readl(GCC_GMAC0_TX_CBCR); |
| reg_val &= ~GCC_CBCR_CLK_ENABLE; |
| writel(reg_val, GCC_GMAC0_TX_CBCR); |
| mdelay(20); |
| |
| reg_val = readl(GCC_GMAC1_RX_CBCR); |
| reg_val &= ~GCC_CBCR_CLK_ENABLE; |
| writel(reg_val, GCC_GMAC1_RX_CBCR); |
| mdelay(20); |
| |
| reg_val = readl(GCC_GMAC1_TX_CBCR); |
| reg_val &= ~GCC_CBCR_CLK_ENABLE; |
| writel(reg_val, GCC_GMAC1_TX_CBCR); |
| mdelay(20); |
| |
| } |
| |
| static void gmac_clk_src_init(void) |
| { |
| u32 reg_val, iGmac_id, iTxRx; |
| |
| /*select source of GMAC*/ |
| reg_val = readl(GCC_GMAC0_RX_CFG_RCGR); |
| reg_val &= ~GCC_GMAC_CFG_RCGR_SRC_SEL_MASK; |
| reg_val |= GCC_GMAC0_RX_SRC_SEL_GEPHY_TX; |
| writel(reg_val, GCC_GMAC0_RX_CFG_RCGR); |
| |
| reg_val = readl(GCC_GMAC0_TX_CFG_RCGR); |
| reg_val &= ~GCC_GMAC_CFG_RCGR_SRC_SEL_MASK; |
| reg_val |= GCC_GMAC0_TX_SRC_SEL_GEPHY_TX; |
| writel(reg_val, GCC_GMAC0_TX_CFG_RCGR); |
| |
| reg_val = readl(GCC_GMAC1_RX_CFG_RCGR); |
| reg_val &= ~GCC_GMAC_CFG_RCGR_SRC_SEL_MASK; |
| reg_val |= GCC_GMAC1_RX_SRC_SEL_UNIPHY_RX; |
| writel(reg_val, GCC_GMAC1_RX_CFG_RCGR); |
| |
| reg_val = readl(GCC_GMAC1_TX_CFG_RCGR); |
| reg_val &= ~GCC_GMAC_CFG_RCGR_SRC_SEL_MASK; |
| reg_val |= GCC_GMAC1_TX_SRC_SEL_UNIPHY_TX; |
| writel(reg_val, GCC_GMAC1_TX_CFG_RCGR); |
| |
| /* update above clock configuration */ |
| for (iGmac_id = 0; iGmac_id < 2; ++iGmac_id) { |
| for (iTxRx = 0; iTxRx < 2; ++iTxRx){ |
| reg_val = 0; |
| reg_val = readl(GCC_GMAC0_RX_CMD_RCGR + |
| (iTxRx * 8) + (iGmac_id * 0x10)); |
| reg_val &= ~0x1; |
| reg_val |= 0x1; |
| writel(reg_val, GCC_GMAC0_RX_CMD_RCGR + |
| (iTxRx * 8) + (iGmac_id * 0x10)); |
| } |
| } |
| reg_val = readl(GCC_GMAC_CFG_RCGR); |
| reg_val = 0x209; |
| writel(reg_val, GCC_GMAC_CFG_RCGR); |
| |
| reg_val = readl(GCC_GMAC_CMD_RCGR); |
| reg_val &= ~0x1; |
| reg_val |= 0x1; |
| writel(reg_val, GCC_GMAC_CMD_RCGR); |
| } |
| |
| static void gephy_reset(void) |
| { |
| u32 reg_val; |
| |
| reg_val = readl(GCC_GEPHY_BCR); |
| writel(reg_val | (GCC_GEPHY_BCR_BLK_ARES), |
| GCC_GEPHY_BCR); |
| mdelay(20); |
| writel(reg_val & (~GCC_GEPHY_BCR_BLK_ARES), |
| GCC_GEPHY_BCR); |
| reg_val = readl(GCC_GEPHY_MISC); |
| writel(reg_val | (GCC_GEPHY_MISC_ARES), |
| GCC_GEPHY_MISC); |
| mdelay(20); |
| writel(reg_val & (~GCC_GEPHY_MISC_ARES), |
| GCC_GEPHY_MISC); |
| } |
| |
| static void uniphy_reset(void) |
| { |
| u32 reg_val; |
| |
| reg_val = readl(GCC_UNIPHY_BCR); |
| writel(reg_val | (GCC_UNIPHY_BCR_BLK_ARES), |
| GCC_UNIPHY_BCR); |
| mdelay(20); |
| writel(reg_val & (~GCC_UNIPHY_BCR_BLK_ARES), |
| GCC_UNIPHY_BCR); |
| } |
| |
| static void gmac_reset(void) |
| { |
| u32 reg_val; |
| |
| reg_val = readl(GCC_GMAC0_BCR); |
| writel(reg_val | (GCC_GMAC0_BCR_BLK_ARES), |
| GCC_GMAC0_BCR); |
| mdelay(20); |
| writel(reg_val & (~GCC_GMAC0_BCR_BLK_ARES), |
| GCC_GMAC0_BCR); |
| |
| reg_val = readl(GCC_GMAC1_BCR); |
| writel(reg_val | (GCC_GMAC1_BCR_BLK_ARES), |
| GCC_GMAC1_BCR); |
| mdelay(200); |
| writel(reg_val & (~GCC_GMAC1_BCR_BLK_ARES), |
| GCC_GMAC1_BCR); |
| |
| } |
| |
| static void cmn_clock_init (void) |
| { |
| u32 reg_val = 0; |
| #ifdef INTERNAL_96MHZ |
| reg_val = readl(CMN_BLK_PLL_SRC_ADDR); |
| reg_val = ((reg_val & PLL_CTRL_SRC_MASK) | |
| (CMN_BLK_PLL_SRC_SEL_FROM_REG << 0x8)); |
| writel(reg_val, CMN_BLK_PLL_SRC_ADDR); |
| reg_val = readl(CMN_BLK_ADDR + 4); |
| reg_val = (reg_val & PLL_REFCLK_DIV_MASK) | PLL_REFCLK_DIV_2; |
| writel(reg_val, CMN_BLK_ADDR + 0x4); |
| #else |
| reg_val = readl(CMN_BLK_ADDR + 4); |
| reg_val = (reg_val & FREQUENCY_MASK) | INTERNAL_48MHZ_CLOCK; |
| writel(reg_val, CMN_BLK_ADDR + 0x4); |
| #endif |
| reg_val = readl(CMN_BLK_ADDR); |
| reg_val = reg_val | 0x40; |
| writel(reg_val, CMN_BLK_ADDR); |
| mdelay(1); |
| reg_val = reg_val & (~0x40); |
| writel(reg_val, CMN_BLK_ADDR); |
| mdelay(1); |
| writel(0xbf, CMN_BLK_ADDR); |
| mdelay(1); |
| writel(0xff, CMN_BLK_ADDR); |
| mdelay(1); |
| } |
| |
| static void cmnblk_enable(void) |
| { |
| u32 reg_val; |
| |
| reg_val = readl(TCSR_ETH_LDO_RDY_REG); |
| reg_val |= ETH_LDO_RDY; |
| writel(reg_val, TCSR_ETH_LDO_RDY_REG); |
| } |
| |
| static void cmnblk_check_state(void) |
| { |
| u32 reg_val, times = 20; |
| |
| while(times--) |
| { |
| reg_val = readl(CMN_PLL_PLL_LOCKED_REG); |
| if(reg_val & CMN_PLL_LOCKED) { |
| printf("cmbblk is stable %x\n", |
| reg_val); |
| break; |
| } |
| mdelay(10); |
| } |
| if(!times) { |
| printf("200ms have been over %x\n", |
| readl(CMN_PLL_PLL_LOCKED_REG)); |
| } |
| } |
| |
| static void gcc_clock_enable(void) |
| { |
| u32 reg_val; |
| |
| reg_val = readl(GCC_MDIO0_BASE + 0x4); |
| reg_val |= 0x1; |
| writel(reg_val, GCC_MDIO0_BASE + 0x4); |
| |
| reg_val = readl(GCC_MDIO0_BASE + 0x14); |
| reg_val |= 0x1; |
| writel(reg_val, GCC_MDIO0_BASE + 0x14); |
| |
| reg_val = readl(GCC_GMAC0_SYS_CBCR); |
| reg_val |= 0x1; |
| writel(reg_val, GCC_GMAC0_SYS_CBCR); |
| |
| reg_val = readl(GCC_GMAC0_PTP_CBCR); |
| reg_val |= 0x1; |
| writel(reg_val, GCC_GMAC0_PTP_CBCR); |
| |
| reg_val = readl(GCC_GMAC0_CFG_CBCR); |
| reg_val |= 0x1; |
| writel(reg_val, GCC_GMAC0_CFG_CBCR); |
| |
| reg_val = readl(GCC_GMAC1_SYS_CBCR); |
| reg_val |= 0x1; |
| writel(reg_val, GCC_GMAC1_SYS_CBCR); |
| |
| reg_val = readl(GCC_GMAC1_PTP_CBCR); |
| reg_val |= 0x1; |
| writel(reg_val, GCC_GMAC1_PTP_CBCR); |
| |
| reg_val = readl(GCC_GMAC1_CFG_CBCR); |
| reg_val |= 0x1; |
| writel(reg_val, GCC_GMAC1_CFG_CBCR); |
| |
| reg_val = readl(GCC_GMAC0_RX_CBCR); |
| reg_val |= 0x1; |
| writel(reg_val, GCC_GMAC0_RX_CBCR); |
| |
| reg_val = readl(GCC_GMAC0_TX_CBCR); |
| reg_val |= 0x1; |
| writel(reg_val, GCC_GMAC0_TX_CBCR); |
| |
| reg_val = readl(GCC_GMAC1_RX_CBCR); |
| reg_val |= 0x1; |
| writel(reg_val, GCC_GMAC1_RX_CBCR); |
| |
| reg_val = readl(GCC_GMAC1_TX_CBCR); |
| reg_val |= 0x1; |
| writel(reg_val, GCC_GMAC1_TX_CBCR); |
| |
| reg_val = readl(GCC_SNOC_GMAC0_AHB_CBCR); |
| reg_val |= 0x1; |
| writel(reg_val, GCC_SNOC_GMAC0_AHB_CBCR); |
| |
| reg_val = readl(GCC_SNOC_GMAC1_AHB_CBCR); |
| reg_val |= 0x1; |
| writel(reg_val, GCC_SNOC_GMAC1_AHB_CBCR); |
| |
| reg_val = readl(GCC_SNOC_GMAC0_AXI_CBCR); |
| reg_val |= 0x1; |
| writel(reg_val, GCC_SNOC_GMAC0_AXI_CBCR); |
| |
| reg_val = readl(GCC_SNOC_GMAC1_AXI_CBCR); |
| reg_val |= 0x1; |
| writel(reg_val, GCC_SNOC_GMAC1_AXI_CBCR); |
| } |
| |
| static void ethernet_clock_enable(void) |
| { |
| cmn_blk_clk_set(); |
| uniphy_clk_set(); |
| gephy_uniphy_clock_disable(); |
| gmac_clock_disable(); |
| gmac_clk_src_init(); |
| cmn_clock_init(); |
| cmnblk_enable(); |
| cmnblk_check_state(); |
| gephy_reset(); |
| uniphy_reset(); |
| gmac_reset(); |
| gcc_clock_enable(); |
| } |
| |
| static void enable_gephy_led(int gpio) |
| { |
| unsigned int *led_gpio_base = |
| (unsigned int *)GPIO_CONFIG_ADDR(gpio); |
| |
| writel(0xc5, led_gpio_base); |
| } |
| |
| int board_eth_init(bd_t *bis) |
| { |
| int status; |
| int led_gpio; |
| int gmac_cfg_node = 0, offset = 0; |
| int loop = 0; |
| int switch_gpio = 0; |
| unsigned int tmp_phy_array[8] = {0}; |
| int inner_loop; |
| |
| gmac_cfg_node = fdt_path_offset(gd->fdt_blob, "/gmac_cfg"); |
| if (gmac_cfg_node >= 0) { |
| /* |
| * Clock enable |
| */ |
| ethernet_clock_enable(); |
| led_gpio = fdtdec_get_uint(gd->fdt_blob, |
| gmac_cfg_node, "gephy_led", 0); |
| if (led_gpio) |
| enable_gephy_led(led_gpio); |
| |
| set_ext_mdio_gpio(gmac_cfg_node); |
| |
| for (offset = fdt_first_subnode(gd->fdt_blob, gmac_cfg_node); |
| offset > 0; |
| offset = fdt_next_subnode(gd->fdt_blob, offset) , loop++) { |
| |
| gmac_cfg[loop].base = fdtdec_get_uint(gd->fdt_blob, |
| offset, "base", 0); |
| |
| gmac_cfg[loop].unit = fdtdec_get_uint(gd->fdt_blob, |
| offset, "unit", 0); |
| |
| gmac_cfg[loop].phy_addr = fdtdec_get_uint(gd->fdt_blob, |
| offset, "phy_address", 0); |
| |
| gmac_cfg[loop].phy_interface_mode = fdtdec_get_uint(gd->fdt_blob, |
| offset, "phy_interface_mode", 0); |
| |
| gmac_cfg[loop].phy_external_link = fdtdec_get_uint(gd->fdt_blob, |
| offset, "phy_external_link", 0); |
| |
| gmac_cfg[loop].phy_napa_gpio = fdtdec_get_uint(gd->fdt_blob, |
| offset, "napa_gpio", 0); |
| if (gmac_cfg[loop].phy_napa_gpio){ |
| reset_napa_phy_gpio(gmac_cfg[loop].phy_napa_gpio); |
| } |
| gmac_cfg[loop].phy_8033_gpio = fdtdec_get_uint(gd->fdt_blob, |
| offset, "8033_gpio", 0); |
| if (gmac_cfg[loop].phy_8033_gpio){ |
| reset_8033_phy_gpio(gmac_cfg[loop].phy_8033_gpio); |
| } |
| switch_gpio = fdtdec_get_uint(gd->fdt_blob, offset, "switch_gpio", 0); |
| if (switch_gpio) { |
| reset_s17c_switch_gpio(switch_gpio); |
| } |
| gmac_cfg[loop].phy_type = fdtdec_get_uint(gd->fdt_blob, |
| offset, "phy_type", -1); |
| |
| gmac_cfg[loop].mac_pwr = fdtdec_get_uint(gd->fdt_blob, |
| offset, "mac_pwr", 0); |
| |
| gmac_cfg[loop].ipq_swith = fdtdec_get_uint(gd->fdt_blob, |
| offset, "s17c_switch_enable", 0); |
| if (gmac_cfg[loop].ipq_swith) { |
| gmac_cfg[loop].switch_port_count = fdtdec_get_uint( |
| gd->fdt_blob, |
| offset, "switch_port_count", 0); |
| |
| fdtdec_get_int_array(gd->fdt_blob, offset, "switch_phy_address", |
| tmp_phy_array, gmac_cfg[loop].switch_port_count); |
| |
| for(inner_loop = 0; inner_loop < gmac_cfg[loop].switch_port_count; |
| inner_loop++){ |
| gmac_cfg[loop].switch_port_phy_address[inner_loop] = |
| (char)tmp_phy_array[inner_loop]; |
| } |
| } |
| } |
| } |
| |
| if (loop < CONFIG_IPQ_NO_MACS) |
| gmac_cfg[loop].unit = -1; |
| |
| status = ipq_gmac_init(gmac_cfg); |
| |
| return status; |
| } |
| |
| void set_flash_secondary_type(qca_smem_flash_info_t *smem) |
| { |
| return; |
| }; |
| |
| #ifdef CONFIG_USB_XHCI_IPQ |
| #ifdef CONFIG_USB_DWC3 |
| static struct dwc3_device dwc3_device_data[CONFIG_USB_MAX_CONTROLLER_COUNT] = |
| { |
| { |
| .maximum_speed = USB_SPEED_SUPER, |
| .base = 0x8A00000, |
| .has_lpm_erratum = true, |
| .dr_mode = USB_DR_MODE_PERIPHERAL, |
| .tx_fifo_resize = true, |
| .lpm_nyet_threshold = 0xff, |
| .is_utmi_l1_suspend = true, |
| .hird_threshold = 16, |
| .tx_de_emphasis = 1, |
| .dis_u3_susphy_quirk = true, |
| .dis_u2_susphy_quirk = true, |
| .index = 0, |
| }, |
| }; |
| |
| void usb_gadget_handle_interrupts(int index) |
| { |
| dwc3_uboot_handle_interrupt(index); |
| } |
| |
| static void usb_bus_override(bool enable) |
| { |
| uint32_t reg; |
| |
| reg = readl(QSCRATCH_BASE + QSCRATCH_SS_PHY_CTRL); |
| if (enable) |
| reg |= LANE0_PWR_PRESENT; |
| else |
| reg &= ~LANE0_PWR_PRESENT; |
| writel(reg, QSCRATCH_BASE + QSCRATCH_SS_PHY_CTRL); |
| |
| reg = readl(QSCRATCH_BASE + QSCRATCH_HS_PHY_CTRL); |
| if (enable) |
| reg |= UTMI_OTG_VBUS_VALID | SW_SESSVLD_SEL; |
| else |
| reg &= ~(UTMI_OTG_VBUS_VALID | SW_SESSVLD_SEL); |
| writel(reg, QSCRATCH_BASE + QSCRATCH_HS_PHY_CTRL); |
| } |
| |
| int board_usb_init(int index, enum usb_init_type init) |
| { |
| int count; |
| |
| usb_bus_override(true); |
| |
| for (count = 0; count < CONFIG_USB_MAX_CONTROLLER_COUNT; ++count){ |
| if (dwc3_device_data[count].index == index){ |
| break; |
| } |
| } |
| if (count == CONFIG_USB_MAX_CONTROLLER_COUNT) { |
| return -ENODEV; |
| } |
| return dwc3_uboot_init(&dwc3_device_data[count]); |
| } |
| |
| int board_usb_cleanup(int index, enum usb_init_type init) |
| { |
| usb_bus_override(false); |
| dwc3_uboot_exit(index); |
| return 0; |
| } |
| #endif |
| |
| void board_usb_deinit(int id) |
| { |
| int nodeoff, ssphy, gpio_node; |
| char node_name[8]; |
| |
| if(readl(EUD_EUD_EN2)) |
| /* |
| * Eud enable skipping deinit part |
| */ |
| return; |
| |
| snprintf(node_name, sizeof(node_name), "usb%d", id); |
| nodeoff = fdt_path_offset(gd->fdt_blob, node_name); |
| if (fdtdec_get_int(gd->fdt_blob, nodeoff, "qcom,emulation", 0)) |
| return; |
| |
| ssphy = fdtdec_get_int(gd->fdt_blob, nodeoff, "ssphy", 0); |
| /* Enable USB PHY Power down */ |
| setbits_le32(QUSB2PHY_BASE + 0xA4, 0x0); |
| /* Disable clocks */ |
| writel(0x0, GCC_USB0_PHY_CFG_AHB_CBCR); |
| writel(0x4220, GCC_USB0_MASTER_CBCR); |
| writel(0x0, GCC_SYS_NOC_USB0_AXI_CBCR); |
| writel(0x0, GCC_USB0_SLEEP_CBCR); |
| writel(0x0, GCC_USB0_MOCK_UTMI_CBCR); |
| writel(0x0, GCC_USB0_AUX_CBCR); |
| writel(0x0, GCC_USB0_LFPS_CBCR); |
| /* GCC_QUSB2_0_PHY_BCR */ |
| set_mdelay_clearbits_le32(GCC_QUSB2_0_PHY_BCR, 0x1, 10); |
| /* GCC_USB0_PHY_BCR */ |
| if (ssphy) |
| set_mdelay_clearbits_le32(GCC_USB0_PHY_BCR, 0x1, 10); |
| /* GCC Reset USB BCR */ |
| set_mdelay_clearbits_le32(GCC_USB0_BCR, 0x1, 10); |
| /* Deselect the usb phy mux */ |
| if (ssphy) |
| writel(0x0, TCSR_USB_PCIE_SEL); |
| |
| /* deinit USB power GPIO for drive 5V */ |
| gpio_node = fdt_subnode_offset(gd->fdt_blob, nodeoff, "usb_gpio"); |
| if (gpio_node >= 0){ |
| gpio_node = fdt_first_subnode(gd->fdt_blob, gpio_node); |
| if (gpio_node > 0) { |
| int gpio = fdtdec_get_uint(gd->fdt_blob, |
| gpio_node, "gpio", 0); |
| unsigned int *gpio_base = |
| (unsigned int *)GPIO_CONFIG_ADDR(gpio); |
| int usb_pwr_gpio = fdtdec_get_int(gd->fdt_blob, nodeoff, "usb_pwr_gpio", 0); |
| writel(0xC1, gpio_base); |
| gpio_set_value(usb_pwr_gpio, GPIO_OUT_LOW); |
| } |
| } |
| } |
| |
| static void usb_clock_init(int id, int ssphy) |
| { |
| int cfg; |
| |
| /* select usb phy mux */ |
| if (ssphy) |
| writel(0x1, TCSR_USB_PCIE_SEL); |
| |
| /* Configure usb0_master_clk_src */ |
| cfg = (GCC_USB0_MASTER_CFG_RCGR_SRC_SEL | |
| GCC_USB0_MASTER_CFG_RCGR_SRC_DIV); |
| writel(cfg, GCC_USB0_MASTER_CFG_RCGR); |
| writel(CMD_UPDATE, GCC_USB0_MASTER_CMD_RCGR); |
| mdelay(100); |
| writel(ROOT_EN, GCC_USB0_MASTER_CMD_RCGR); |
| |
| /* Configure usb0_mock_utmi_clk_src */ |
| cfg = (GCC_USB_MOCK_UTMI_SRC_SEL | |
| GCC_USB_MOCK_UTMI_SRC_DIV); |
| writel(cfg, GCC_USB0_MOCK_UTMI_CFG_RCGR); |
| writel(GCC_USB_MOCK_UTMI_CLK_DIV, GCC_USB0_MOCK_UTMI_CBCR); |
| writel(CMD_UPDATE, GCC_USB0_MOCK_UTMI_CMD_RCGR); |
| mdelay(100); |
| writel(ROOT_EN, GCC_USB0_MOCK_UTMI_CMD_RCGR); |
| |
| /* Configure usb0_aux_clk_src */ |
| cfg = (GCC_USB0_AUX_CFG_SRC_SEL | |
| GCC_USB0_AUX_CFG_SRC_DIV); |
| writel(cfg, GCC_USB0_AUX_CFG_RCGR); |
| writel(CMD_UPDATE, GCC_USB0_AUX_CMD_RCGR); |
| mdelay(100); |
| writel(ROOT_EN, GCC_USB0_AUX_CMD_RCGR); |
| |
| /* Configure usb0_lfps_cmd_rcgr */ |
| cfg = (GCC_USB0_LFPS_CFG_SRC_SEL | |
| GCC_USB0_LFPS_CFG_SRC_DIV); |
| writel(cfg, GCC_USB0_LFPS_CFG_RCGR); |
| writel(LFPS_M, GCC_USB0_LFPS_M); |
| writel(LFPS_N, GCC_USB0_LFPS_N); |
| writel(LFPS_D, GCC_USB0_LFPS_D); |
| writel(readl(GCC_USB0_LFPS_CFG_RCGR) | GCC_USB0_LFPS_MODE, |
| GCC_USB0_LFPS_CFG_RCGR); |
| writel(CMD_UPDATE, GCC_USB0_LFPS_CMD_RCGR); |
| mdelay(100); |
| writel(ROOT_EN, GCC_USB0_LFPS_CMD_RCGR); |
| |
| /* Configure CBCRs */ |
| writel(CLK_DISABLE, GCC_SYS_NOC_USB0_AXI_CBCR); |
| writel(CLK_ENABLE, GCC_SYS_NOC_USB0_AXI_CBCR); |
| writel((readl(GCC_USB0_MASTER_CBCR) | CLK_ENABLE), |
| GCC_USB0_MASTER_CBCR); |
| writel(CLK_ENABLE, GCC_USB0_SLEEP_CBCR); |
| writel((GCC_USB_MOCK_UTMI_CLK_DIV | CLK_ENABLE), |
| GCC_USB0_MOCK_UTMI_CBCR); |
| writel(CLK_DISABLE, GCC_USB0_PIPE_CBCR); |
| writel(CLK_ENABLE, GCC_USB0_PHY_CFG_AHB_CBCR); |
| writel(CLK_ENABLE, GCC_USB0_AUX_CBCR); |
| writel(CLK_ENABLE, GCC_USB0_LFPS_CBCR); |
| } |
| |
| static void usb_init_hsphy(void __iomem *phybase, int ssphy) |
| { |
| if (!ssphy) { |
| /*Enable utmi instead of pipe*/ |
| writel((readl(USB30_GENERAL_CFG) | PIPE_UTMI_CLK_DIS), USB30_GENERAL_CFG); |
| |
| udelay(100); |
| |
| writel((readl(USB30_GENERAL_CFG) | PIPE_UTMI_CLK_SEL | PIPE3_PHYSTATUS_SW), USB30_GENERAL_CFG); |
| |
| udelay(100); |
| |
| writel((readl(USB30_GENERAL_CFG) & ~PIPE_UTMI_CLK_DIS), USB30_GENERAL_CFG); |
| } |
| /* Disable USB PHY Power down */ |
| setbits_le32(phybase + 0xA4, 0x1); |
| /* Enable override ctrl */ |
| writel(UTMI_PHY_OVERRIDE_EN, phybase + USB_PHY_CFG0); |
| /* Enable POR*/ |
| writel(POR_EN, phybase + USB_PHY_UTMI_CTRL5); |
| udelay(15); |
| /* Configure frequency select value*/ |
| writel(FREQ_SEL, phybase + USB_PHY_FSEL_SEL); |
| /* Configure refclk frequency */ |
| writel(COMMONONN | FSEL | RETENABLEN, |
| phybase + USB_PHY_HS_PHY_CTRL_COMMON0); |
| /* select refclk source */ |
| writel(CLKCORE, phybase + USB_PHY_REFCLK_CTRL); |
| /* select ATERESET*/ |
| writel(POR_EN & ATERESET, phybase + USB_PHY_UTMI_CTRL5); |
| writel(USB2_SUSPEND_N_SEL | USB2_SUSPEND_N | USB2_UTMI_CLK_EN, |
| phybase + USB_PHY_HS_PHY_CTRL2); |
| writel(0x0, phybase + USB_PHY_UTMI_CTRL5); |
| writel(USB2_SUSPEND_N | USB2_UTMI_CLK_EN, |
| phybase + USB_PHY_HS_PHY_CTRL2); |
| /* Disable override ctrl */ |
| writel(0x0, phybase + USB_PHY_CFG0); |
| } |
| |
| static void usb_init_ssphy(void __iomem *phybase) |
| { |
| writel(CLK_ENABLE, GCC_USB0_PHY_CFG_AHB_CBCR); |
| writel(CLK_ENABLE, GCC_USB0_PIPE_CBCR); |
| udelay(100); |
| /*set frequency initial value*/ |
| writel(0x1cb9, phybase + SSCG_CTRL_REG_4); |
| writel(0x023a, phybase + SSCG_CTRL_REG_5); |
| /*set spectrum spread count*/ |
| writel(0xd360, phybase + SSCG_CTRL_REG_3); |
| /*set fstep*/ |
| writel(0x1, phybase + SSCG_CTRL_REG_1); |
| writel(0xeb, phybase + SSCG_CTRL_REG_2); |
| return; |
| } |
| |
| static void usb_init_phy(int index, int ssphy) |
| { |
| void __iomem *boot_clk_ctl, *usb_bcr, *qusb2_phy_bcr; |
| |
| boot_clk_ctl = (u32 *)GCC_USB_0_BOOT_CLOCK_CTL; |
| usb_bcr = (u32 *)GCC_USB0_BCR; |
| qusb2_phy_bcr = (u32 *)GCC_QUSB2_0_PHY_BCR; |
| |
| /* Disable USB Boot Clock */ |
| clrbits_le32(boot_clk_ctl, 0x0); |
| |
| /* GCC Reset USB BCR */ |
| set_mdelay_clearbits_le32(usb_bcr, 0x1, 10); |
| |
| if (ssphy) |
| setbits_le32(GCC_USB0_PHY_BCR, 0x1); |
| setbits_le32(qusb2_phy_bcr, 0x1); |
| udelay(1); |
| /* Config user control register */ |
| writel(0x4004010, USB30_GUCTL); |
| writel(0x4945920, USB30_FLADJ); |
| if (ssphy) |
| clrbits_le32(GCC_USB0_PHY_BCR, 0x1); |
| clrbits_le32(qusb2_phy_bcr, 0x1); |
| udelay(30); |
| |
| if (ssphy) |
| usb_init_ssphy((u32 *)USB3PHY_APB_BASE); |
| usb_init_hsphy((u32 *)QUSB2PHY_BASE, ssphy); |
| } |
| |
| int ipq_board_usb_init(void) |
| { |
| int i, nodeoff, ssphy, gpio_node, usb_pwr_gpio; |
| char node_name[8]; |
| |
| if(readl(EUD_EUD_EN2)) { |
| printf("USB: EUD Enable, skipping initialization\n"); |
| return 0; |
| } |
| |
| for (i=0; i<CONFIG_USB_MAX_CONTROLLER_COUNT; i++) { |
| snprintf(node_name, sizeof(node_name), "usb%d", i); |
| nodeoff = fdt_path_offset(gd->fdt_blob, node_name); |
| if (nodeoff < 0){ |
| printf("USB: Node Not found, skipping initialization\n"); |
| return 0; |
| } |
| |
| ssphy = fdtdec_get_int(gd->fdt_blob, nodeoff, "ssphy", 0); |
| if (!fdtdec_get_int(gd->fdt_blob, nodeoff, "qcom,emulation", 0)) { |
| |
| usb_clock_init(i, ssphy); |
| usb_init_phy(i, ssphy); |
| }else { |
| /* Config user control register */ |
| writel(0x0C804010, USB30_GUCTL); |
| } |
| } |
| |
| /* USB power GPIO for drive 5V */ |
| gpio_node = |
| fdt_subnode_offset(gd->fdt_blob, nodeoff, "usb_gpio"); |
| if (gpio_node >= 0) { |
| qca_gpio_init(gpio_node); |
| usb_pwr_gpio = fdtdec_get_int(gd->fdt_blob, nodeoff, "usb_pwr_gpio", 0); |
| gpio_set_value(usb_pwr_gpio, GPIO_OUT_HIGH); |
| } |
| |
| return 0; |
| } |
| #endif |
| |
| #ifdef CONFIG_PCI_IPQ |
| static void pcie_v2_clock_init(int lane) |
| { |
| #ifdef CONFIG_PCI |
| u32 reg_val; |
| void __iomem *base; |
| |
| /*single lane*/ |
| /* Enable SYS_NOC clock */ |
| if (lane == 1) { |
| base = (void __iomem *)GCC_PCIE1_BOOT_CLOCK_CTL; |
| writel(CLK_ENABLE, GCC_SYS_NOC_PCIE1_AXI_CBCR); |
| mdelay(1); |
| /* Configure pcie1_aux_clk_src */ |
| writel((GCC_PCIE1_AUX_CFG_RCGR_SRC_SEL | |
| GCC_PCIE1_AUX_CFG_RCGR_SRC_DIV), |
| base + PCIE_AUX_CFG_RCGR); |
| mdelay(1); |
| reg_val = readl(base + PCIE_AUX_CMD_RCGR); |
| reg_val &= ~0x1; |
| reg_val |= 0x1; |
| writel(reg_val, base + PCIE_AUX_CMD_RCGR); |
| |
| /* Configure pcie1_axi_clk_src */ |
| writel((GCC_PCIE1_AXI_CFG_RCGR_SRC_SEL | |
| GCC_PCIE1_AXI_CFG_RCGR_SRC_DIV), |
| base + PCIE_AXI_CFG_RCGR); |
| mdelay(1); |
| reg_val = readl(base + PCIE_AXI_CMD_RCGR); |
| reg_val &= ~0x1; |
| reg_val |= 0x1; |
| writel(reg_val, base + PCIE_AXI_CMD_RCGR); |
| } else { /*double lane*/ |
| base = (void __iomem *)GCC_PCIE0_BOOT_CLOCK_CTL; |
| writel(CLK_ENABLE, GCC_SYS_NOC_PCIE0_AXI_CBCR); |
| mdelay(1); |
| /* Configure pcie1_aux_clk_src */ |
| writel((GCC_PCIE0_AUX_CFG_RCGR_SRC_SEL | |
| GCC_PCIE0_AUX_CFG_RCGR_SRC_DIV), |
| base + PCIE_AUX_CFG_RCGR); |
| mdelay(1); |
| reg_val = readl(base + PCIE_AUX_CMD_RCGR); |
| reg_val &= ~0x1; |
| reg_val |= 0x1; |
| writel(reg_val, base + PCIE_AUX_CMD_RCGR); |
| |
| /* Configure pcie1_axi_clk_src */ |
| writel((GCC_PCIE0_AXI_CFG_RCGR_SRC_SEL | |
| GCC_PCIE0_AXI_CFG_RCGR_SRC_DIV), |
| base + PCIE_AXI_CFG_RCGR); |
| mdelay(1); |
| reg_val = readl(base + PCIE_AXI_CMD_RCGR); |
| reg_val &= ~0x1; |
| reg_val |= 0x1; |
| writel(reg_val, base + PCIE_AXI_CMD_RCGR); |
| } |
| mdelay(1); |
| reg_val= readl(base + PCIE_AXI_M_CBCR); |
| reg_val |= CLK_ENABLE; |
| writel(reg_val, base + PCIE_AXI_M_CBCR); |
| |
| mdelay(1); |
| reg_val = readl(base + PCIE_AXI_S_CBCR); |
| reg_val |= CLK_ENABLE; |
| writel(reg_val, base + PCIE_AXI_S_CBCR); |
| |
| mdelay(1); |
| writel(CLK_ENABLE, base + PCIE_AHB_CBCR); |
| |
| mdelay(1); |
| writel(CLK_ENABLE, base + PCIE_AUX_CBCR); |
| |
| mdelay(1); |
| writel(CLK_ENABLE, base + PCIE_AXI_S_BRIDGE_CBCR); |
| |
| mdelay(1); |
| reg_val= readl(base + PCIE_PIPE_CBCR); |
| reg_val |= CLK_ENABLE; |
| writel(reg_val, base + PCIE_PIPE_CBCR); |
| mdelay(1); |
| #endif |
| return; |
| } |
| |
| static void pcie_v2_clock_deinit(int lane) |
| { |
| #ifdef CONFIG_PCI |
| void __iomem *base; |
| |
| /*single lane*/ |
| if (lane == 1) { |
| base = (void __iomem *)GCC_PCIE1_BOOT_CLOCK_CTL; |
| writel(0x0, GCC_SYS_NOC_PCIE1_AXI_CBCR); |
| } else { /*double lane*/ |
| base = (void __iomem *)GCC_PCIE0_BOOT_CLOCK_CTL; |
| writel(0x0, GCC_SYS_NOC_PCIE0_AXI_CBCR); |
| } |
| mdelay (5); |
| writel(0x0, base + PCIE_AHB_CBCR); |
| writel(0x0, base + PCIE_AXI_M_CBCR); |
| writel(0x0, base + PCIE_AXI_S_CBCR); |
| writel(0x0, base + PCIE_AUX_CBCR); |
| writel(0x0, base + PCIE_PIPE_CBCR); |
| writel(0x0, base + PCIE_AXI_S_BRIDGE_CBCR); |
| #endif |
| return; |
| } |
| |
| static void pcie_phy_init(u32 reg_base, int mode, int lane) |
| { |
| int i; |
| for (i = 0; i < lane; ++i) { |
| /*set frequency initial value*/ |
| writel(0x1cb9, (reg_base + (i * 0x800)) + SSCG_CTRL_REG_4); |
| writel(0x023a, (reg_base + (i * 0x800)) + SSCG_CTRL_REG_5); |
| /*set spectrum spread count*/ |
| writel(0x1360, (reg_base + (i * 0x800)) + SSCG_CTRL_REG_3); |
| if (mode == 1) { |
| /*set fstep*/ |
| writel(0x0, (reg_base + (i * 0x800)) + |
| SSCG_CTRL_REG_1); |
| writel(0x0, (reg_base + (i * 0x800)) + |
| SSCG_CTRL_REG_2); |
| } else { |
| /*set fstep*/ |
| writel(0x1, (reg_base + (i * 0x800)) + |
| SSCG_CTRL_REG_1); |
| writel(0xeb, (reg_base + (i * 0x800)) + |
| SSCG_CTRL_REG_2); |
| /*set FLOOP initial value*/ |
| writel(0x3f9, (reg_base + (i * 0x800)) + |
| CDR_CTRL_REG_4); |
| writel(0x1c9, (reg_base + (i * 0x800)) + |
| CDR_CTRL_REG_5); |
| /*set upper boundary level*/ |
| writel(0x419, (reg_base + (i * 0x800)) + |
| CDR_CTRL_REG_2); |
| /*set fixed offset*/ |
| writel(0x200, (reg_base + (i * 0x800)) + |
| CDR_CTRL_REG_1); |
| } |
| } |
| } |
| |
| static void pcie_reset(int lane) |
| { |
| u32 reg_val; |
| void __iomem *base; |
| |
| /*single lane*/ |
| if (lane == 1) |
| base = (void __iomem *)GCC_PCIE1_BOOT_CLOCK_CTL; |
| else /*double lane*/ |
| base = (void __iomem *)GCC_PCIE0_BOOT_CLOCK_CTL; |
| |
| reg_val = readl(base + PCIE_BCR); |
| writel(reg_val | GCC_PCIE_BCR_ENABLE, |
| (base + PCIE_BCR)); |
| mdelay(1); |
| writel(reg_val & (~GCC_PCIE_BCR_ENABLE), |
| (base + PCIE_BCR)); |
| |
| reg_val = readl(base + PCIE_PHY_BCR); |
| writel(reg_val | GCC_PCIE_BLK_ARES, |
| (base + PCIE_PHY_BCR)); |
| mdelay(1); |
| writel(reg_val & (~GCC_PCIE_BLK_ARES), |
| (base + PCIE_PHY_BCR)); |
| |
| reg_val = readl(base + PCIE_PHY_PHY_BCR); |
| writel(reg_val | GCC_PCIE_BLK_ARES, |
| (base + PCIE_PHY_PHY_BCR)); |
| mdelay(1); |
| writel(reg_val & (~GCC_PCIE_BLK_ARES), |
| (base + PCIE_PHY_PHY_BCR)); |
| |
| reg_val = readl(base + PCIE_MISC_RESET); |
| writel(reg_val | GCC_PCIE_PIPE_ARES, |
| (base + PCIE_MISC_RESET)); |
| mdelay(1); |
| writel(reg_val & (~GCC_PCIE_PIPE_ARES), |
| (base + PCIE_MISC_RESET)); |
| |
| reg_val = readl(base + PCIE_MISC_RESET); |
| writel(reg_val | GCC_PCIE_SLEEP_ARES, |
| (base + PCIE_MISC_RESET)); |
| mdelay(1); |
| writel(reg_val & (~GCC_PCIE_SLEEP_ARES), |
| (base + PCIE_MISC_RESET)); |
| |
| reg_val = readl(base + PCIE_MISC_RESET); |
| writel(reg_val | GCC_PCIE_CORE_STICKY_ARES, |
| (base + PCIE_MISC_RESET)); |
| mdelay(1); |
| writel(reg_val & (~GCC_PCIE_CORE_STICKY_ARES), |
| (base + PCIE_MISC_RESET)); |
| |
| reg_val = readl(base + PCIE_MISC_RESET); |
| writel(reg_val | GCC_PCIE_AXI_MASTER_ARES, |
| (base + PCIE_MISC_RESET)); |
| mdelay(1); |
| writel(reg_val & (~GCC_PCIE_AXI_MASTER_ARES), |
| (base + PCIE_MISC_RESET)); |
| |
| reg_val = readl(base + PCIE_MISC_RESET); |
| writel(reg_val | GCC_PCIE_AXI_SLAVE_ARES, |
| (base + PCIE_MISC_RESET)); |
| mdelay(1); |
| writel(reg_val & (~GCC_PCIE_AXI_SLAVE_ARES), |
| (base + PCIE_MISC_RESET)); |
| |
| reg_val = readl(base + PCIE_MISC_RESET); |
| writel(reg_val | GCC_PCIE_AHB_ARES, |
| (base + PCIE_MISC_RESET)); |
| mdelay(1); |
| writel(reg_val & (~GCC_PCIE_AHB_ARES), |
| (base + PCIE_MISC_RESET)); |
| |
| reg_val = readl(base + PCIE_MISC_RESET); |
| writel(reg_val | GCC_PCI_AXI_MASTER_STICKY_ARES, |
| (base + PCIE_MISC_RESET)); |
| mdelay(1); |
| writel(reg_val & (~GCC_PCI_AXI_MASTER_STICKY_ARES), |
| (base + PCIE_MISC_RESET)); |
| |
| reg_val = readl(base + PCIE_MISC_RESET); |
| writel(reg_val | GCC_PCI_AXI_SLAVE_STICKY_ARES, |
| (base + PCIE_MISC_RESET)); |
| mdelay(1); |
| writel(reg_val & (~GCC_PCI_AXI_SLAVE_STICKY_ARES), |
| (base + PCIE_MISC_RESET)); |
| } |
| |
| void board_pci_init(int id) |
| { |
| int node, gpio_node, mode = 0; |
| struct fdt_resource pci_phy; |
| char name[16]; |
| int err, lane; |
| |
| snprintf(name, sizeof(name), "pci%d", id); |
| node = fdt_path_offset(gd->fdt_blob, name); |
| if (node < 0) { |
| printf("Could not find PCI in device tree\n"); |
| return; |
| } |
| |
| err = fdt_get_named_resource(gd->fdt_blob, node, |
| "reg", "reg-names", "pci_phy",&pci_phy); |
| if (err < 0) |
| return; |
| |
| if (!strcmp(fdt_getprop(gd->fdt_blob, node, "mode", NULL), "fixed")){ |
| mode = 1; |
| } |
| lane = fdtdec_get_int(gd->fdt_blob, node, "lane", 0); |
| |
| gpio_node = fdt_subnode_offset(gd->fdt_blob, node, "pci_gpio"); |
| if (gpio_node >= 0) |
| qca_gpio_init(gpio_node); |
| |
| pcie_reset(lane); |
| pcie_v2_clock_init(lane); |
| pcie_phy_init(pci_phy.start, mode, lane); |
| |
| return; |
| } |
| |
| void board_pci_deinit() |
| { |
| int node, gpio_node, i, lane, err; |
| char name[16]; |
| struct fdt_resource parf; |
| struct fdt_resource pci_phy; |
| |
| for (i = 0; i < PCI_MAX_DEVICES; i++) { |
| snprintf(name, sizeof(name), "pci%d", i); |
| node = fdt_path_offset(gd->fdt_blob, name); |
| if (node < 0) { |
| printf("Could not find PCI in device tree\n"); |
| continue; |
| } |
| err = fdt_get_named_resource(gd->fdt_blob, node, "reg", "reg-names", "parf", |
| &parf); |
| writel(0x0, parf.start + 0x358); |
| writel(0x1, parf.start + 0x40); |
| err = fdt_get_named_resource(gd->fdt_blob, node, "reg", "reg-names", "pci_phy", |
| &pci_phy); |
| if (err < 0) |
| continue; |
| |
| writel(0x1, pci_phy.start + 800); |
| writel(0x0, pci_phy.start + 804); |
| gpio_node = fdt_subnode_offset(gd->fdt_blob, node, "pci_gpio"); |
| if (gpio_node >= 0) |
| qca_gpio_deinit(gpio_node); |
| |
| lane = fdtdec_get_int(gd->fdt_blob, node, "lane", 0); |
| pcie_v2_clock_deinit(lane); |
| } |
| |
| return ; |
| } |
| #endif |
| |
| void fdt_fixup_qpic(void *blob) |
| { |
| int node_off, ret; |
| const char *qpic_node = {"/soc/qpic-nand@79b0000"}; |
| |
| /* This fixup is for qpic io_macro_clk |
| * frequency & phase value |
| */ |
| node_off = fdt_path_offset(blob, qpic_node); |
| if (node_off < 0) { |
| printf("%s: QPIC: unable to find node '%s'\n", |
| __func__, qpic_node); |
| return; |
| } |
| |
| ret = fdt_setprop_u32(blob, node_off, "qcom,iomacromax_clk", qpic_frequency); |
| if (ret) { |
| printf("%s : Unable to set property 'qcom,iomacromax_clk'\n",__func__); |
| return; |
| } |
| |
| ret = fdt_setprop_u32(blob, node_off, "qcom,phase", qpic_phase); |
| if (ret) { |
| printf("%s : Unable to set property 'qcom,phase'\n",__func__); |
| return; |
| } |
| } |
| |
| #ifdef CONFIG_IPQ_TINY |
| void fdt_fixup_art_format(void *blob) |
| { |
| int nodeoffset; |
| nodeoffset = fdt_path_offset(blob, "/"); |
| fdt_add_subnode(blob, nodeoffset, "compressed_art"); |
| |
| } |
| #endif |
| |
| void run_tzt(void *address) |
| { |
| execute_tzt(address); |
| } |
| |
| void fdt_fixup_set_dload_warm_reset(void *blob) |
| { |
| int nodeoff, ret; |
| uint32_t setval = 1; |
| |
| nodeoff = fdt_path_offset(blob, "/soc/qca,scm_restart_reason"); |
| if (nodeoff < 0) { |
| nodeoff = fdt_path_offset(blob, "/qti,scm_restart_reason"); |
| if (nodeoff < 0) { |
| printf("fixup_set_dload: unable to find scm_restart_reason node\n"); |
| return; |
| } |
| } |
| |
| ret = fdt_setprop_u32(blob, nodeoff, "dload_status", setval); |
| if (ret) |
| printf("fixup_set_dload: 'dload_status' not set"); |
| |
| ret = fdt_setprop_u32(blob, nodeoff, "dload_warm_reset", setval); |
| if (ret) |
| printf("fixup_set_dload: 'dload_warm_reset' not set"); |
| } |
| |
| #ifdef CONFIG_SMP_CMD_SUPPORT |
| int is_secondary_core_off(unsigned int cpuid) |
| { |
| int err; |
| |
| err = __invoke_psci_fn_smc(ARM_PSCI_TZ_FN_AFFINITY_INFO, cpuid, 0, 0); |
| |
| return err; |
| } |
| |
| void bring_secondary_core_down(unsigned int state) |
| { |
| __invoke_psci_fn_smc(ARM_PSCI_TZ_FN_CPU_OFF, state, 0, 0); |
| } |
| |
| int bring_sec_core_up(unsigned int cpuid, unsigned int entry, unsigned int arg) |
| { |
| int err; |
| |
| err = __invoke_psci_fn_smc(ARM_PSCI_TZ_FN_CPU_ON, cpuid, entry, arg); |
| if (err) { |
| printf("Enabling CPU%d via psci failed!\n", cpuid); |
| return -1; |
| } |
| |
| printf("Enabled CPU%d via psci successfully!\n", cpuid); |
| return 0; |
| } |
| #endif |
| |
| int get_soc_hw_version(void) |
| { |
| return readl(TCSR_SOC_HW_VERSION_REG); |
| } |
| |
| void sdi_disable(void) |
| { |
| qca_scm_sdi(); |
| } |