blob: 2b4dcc1d2c7c1cd4d6d4c9164e900a7815e34a06 [file] [log] [blame]
/*
* 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();
}