diff options
Diffstat (limited to 'src')
32 files changed, 5622 insertions, 0 deletions
diff --git a/src/soc/qualcomm/ipq40xx/Kconfig b/src/soc/qualcomm/ipq40xx/Kconfig new file mode 100644 index 0000000000..a122ac9eb2 --- /dev/null +++ b/src/soc/qualcomm/ipq40xx/Kconfig @@ -0,0 +1,34 @@ +config SOC_QC_IPQ40XX + bool + default n + select ARCH_BOOTBLOCK_ARMV7 + select ARCH_VERSTAGE_ARMV7 + select ARCH_ROMSTAGE_ARMV7 + select ARCH_RAMSTAGE_ARMV7 + select BOOTBLOCK_CONSOLE + select HAVE_UART_SPECIAL + select SPI_ATOMIC_SEQUENCING + select GENERIC_GPIO_LIB + +if SOC_QC_IPQ40XX + +config CHROMEOS + select CHROMEOS_VBNV_FLASH + select SEPARATE_VERSTAGE + select RETURN_FROM_VERSTAGE + +config MBN_ENCAPSULATION + depends on USE_BLOBS + bool "bootblock encapsulation for ipq40xx" + default y + +config SBL_BLOB + depends on USE_BLOBS + string "file name of the Qualcomm SBL blob" + default "3rdparty/blobs/cpu/qualcomm/ipq40xx/uber-sbl.mbn" + help + The path and filename of the binary blob containing + ipq40xx early initialization code, as supplied by the + vendor. + +endif diff --git a/src/soc/qualcomm/ipq40xx/Makefile.inc b/src/soc/qualcomm/ipq40xx/Makefile.inc new file mode 100644 index 0000000000..95a78b3ce9 --- /dev/null +++ b/src/soc/qualcomm/ipq40xx/Makefile.inc @@ -0,0 +1,84 @@ +## +## This file is part of the coreboot project. +## +## Copyright 2014 Google Inc. +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; version 2 of the License. +## +## 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. +## + +ifeq ($(CONFIG_SOC_QC_IPQ40XX),y) + +bootblock-y += clock.c +bootblock-y += gpio.c +bootblock-$(CONFIG_SPI_FLASH) += spi.c +bootblock-y += timer.c +bootblock-$(CONFIG_DRIVERS_UART) += uart.c + +verstage-y += clock.c +verstage-y += gpio.c +libverstage-y += gsbi.c +libverstage-y += i2c.c +libverstage-y += qup.c +libverstage-y += spi.c +verstage-y += timer.c +verstage-$(CONFIG_DRIVERS_UART) += uart.c + +romstage-y += clock.c +romstage-y += blobs_init.c +romstage-y += gpio.c +romstage-$(CONFIG_SPI_FLASH) += spi.c +romstage-y += timer.c +romstage-$(CONFIG_DRIVERS_UART) += uart.c +romstage-y += cbmem.c + +ramstage-y += blobs_init.c +ramstage-y += cbmem.c +ramstage-y += clock.c +ramstage-y += gpio.c +ramstage-y += lcc.c +ramstage-y += soc.c +ramstage-$(CONFIG_SPI_FLASH) += spi.c +ramstage-y += timer.c +ramstage-y += uart.c # Want the UART always ready for the kernels' earlyprintk +ramstage-y += usb.c +ramstage-y += tz_wrapper.S + +ifeq ($(CONFIG_USE_BLOBS),y) + +# Add MBN header to allow SBL3 to start coreboot bootblock +$(objcbfs)/bootblock.mbn: $(objcbfs)/bootblock.raw.bin + @printf " ADD MBN $(subst $(obj)/,,$(@))\n" + ./util/ipqheader/ipqheader.py $(call loadaddr,bootblock) $< $@.tmp + @mv $@.tmp $@ + +# Create a complete bootblock which will start up the system +$(objcbfs)/bootblock.bin: $(call strip_quotes,$(CONFIG_SBL_BLOB)) \ + $(objcbfs)/bootblock.mbn + @printf " MBNCAT $(subst $(obj)/,,$(@))\n" + @util/ipqheader/mbncat.py -o $@.tmp $^ + @mv $@.tmp $@ + +endif + +CPPFLAGS_common += -Isrc/soc/qualcomm/ipq40xx/include + +# List of binary blobs coreboot needs in CBFS to be able to boot up this SOC +mbn-files := cdt.mbn ddr.mbn rpm.mbn tz.mbn + +# Location of the binary blobs +mbn-root := 3rdparty/blobs/cpu/qualcomm/ipq40xx + +# Create make variables to aid cbfs-files-handler in processing the blobs (add +# them all as raw binaries at the root level). +$(foreach f,$(mbn-files),$(eval cbfs-files-y += $(f))\ + $(eval $(f)-file := $(mbn-root)/$(f))\ + $(eval $(f)-type := raw)) + +endif diff --git a/src/soc/qualcomm/ipq40xx/blobs_init.c b/src/soc/qualcomm/ipq40xx/blobs_init.c new file mode 100644 index 0000000000..5b19fc1d36 --- /dev/null +++ b/src/soc/qualcomm/ipq40xx/blobs_init.c @@ -0,0 +1,155 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2014 Google Inc. + * Copyright (c) 2014, 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 as published by + * the Free Software Foundation; version 2 of the License. + * + * 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 <arch/cache.h> +#include <arch/io.h> +#include <cbfs.h> +#include <console/console.h> +#include <string.h> +#include <timer.h> + +#include <soc/iomap.h> +#include <soc/soc_services.h> + +#include "mbn_header.h" + +static void *load_ipq_blob(const char *file_name) +{ + struct mbn_header *blob_mbn; + void *blob_dest; + size_t blob_size; + + blob_mbn = cbfs_boot_map_with_leak(file_name, CBFS_TYPE_RAW, + &blob_size); + if (!blob_mbn) + return NULL; + + /* some sanity checks on the headers */ + if ((blob_mbn->mbn_version != 3) || + (blob_mbn->mbn_total_size > blob_size)) + return NULL; + + blob_dest = (void *) blob_mbn->mbn_destination; + if (blob_mbn->mbn_destination) { + /* Copy the blob to the appropriate memory location. */ + memcpy(blob_dest, blob_mbn + 1, blob_mbn->mbn_total_size); + cache_sync_instructions(); + return blob_dest; + } + + /* + * The blob did not have to be relocated, return its address in CBFS + * cache. + */ + return blob_mbn + 1; +} + +#ifdef __PRE_RAM__ + +#define DDR_VERSION() ((const char *)0x2a03f600) +#define MAX_DDR_VERSION_SIZE 48 + +int initialize_dram(void) +{ + void *cdt; + int (*ddr_init_function)(void *cdt_header); + + cdt = load_ipq_blob("cdt.mbn"); + ddr_init_function = load_ipq_blob("ddr.mbn"); + + if (!cdt || !ddr_init_function) { + printk(BIOS_ERR, "cdt: %p, ddr_init_function: %p\n", + cdt, ddr_init_function); + die("could not find DDR initialization blobs\n"); + } + + if (ddr_init_function(cdt) < 0) + die("Fail to Initialize DDR\n"); + + /* + * Once DDR initializer finished, its verison can be found at a fixed + * address in SRAM. + */ + printk(BIOS_INFO, "DDR version %.*s initialized\n", + MAX_DDR_VERSION_SIZE, DDR_VERSION()); + + return 0; +} + +#else /* __PRE_RAM__ */ + +void start_tzbsp(void) +{ + void *tzbsp = load_ipq_blob("tz.mbn"); + + if (!tzbsp) + die("could not find or map TZBSP\n"); + + printk(BIOS_INFO, "Starting TZBSP\n"); + + tz_init_wrapper(0, 0, tzbsp); +} + +/* RPM version is encoded in a 32 bit word at the fixed address */ +#define RPM_VERSION() (*((u32 *)(0x00108008))) +void start_rpm(void) +{ + u32 load_addr; + u32 ready_mask = 1 << 10; + u32 rpm_version; + + struct stopwatch sw; + + if (read32(RPM_SIGNAL_COOKIE) == RPM_FW_MAGIC_NUM) { + printk(BIOS_INFO, "RPM appears to have already started\n"); + return; + } + + load_addr = (u32) load_ipq_blob("rpm.mbn"); + if (!load_addr) + die("could not find or map RPM code\n"); + + printk(BIOS_INFO, "Starting RPM\n"); + + /* Clear 'ready' indication. */ + /* + * RPM_INT_ACK is clear-on-write type register, + * read-modify-write is not recommended. + */ + write32(RPM_INT_ACK, ready_mask); + + /* Set RPM entry address */ + write32(RPM_SIGNAL_ENTRY, load_addr); + /* Set cookie */ + write32(RPM_SIGNAL_COOKIE, RPM_FW_MAGIC_NUM); + + /* Wait for RPM start indication, up to 100ms. */ + stopwatch_init_usecs_expire(&sw, 100000); + while (!(read32(RPM_INT) & ready_mask)) + if (stopwatch_expired(&sw)) + die("RPM Initialization failed\n"); + + /* Acknowledge RPM initialization */ + write32(RPM_INT_ACK, ready_mask); + + /* Report RPM version, it is encoded in a 32 bit value. */ + rpm_version = RPM_VERSION(); + printk(BIOS_INFO, "Started RPM version %d.%d.%d\n", + rpm_version >> 24, + (rpm_version >> 16) & 0xff, + rpm_version & 0xffff); +} +#endif /* !__PRE_RAM__ */ diff --git a/src/soc/qualcomm/ipq40xx/cbmem.c b/src/soc/qualcomm/ipq40xx/cbmem.c new file mode 100644 index 0000000000..7aff231be7 --- /dev/null +++ b/src/soc/qualcomm/ipq40xx/cbmem.c @@ -0,0 +1,22 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2014 Google Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * 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 <cbmem.h> +#include <soc/soc_services.h> + +void *cbmem_top(void) +{ + return _memlayout_cbmem_top; +} diff --git a/src/soc/qualcomm/ipq40xx/clock.c b/src/soc/qualcomm/ipq40xx/clock.c new file mode 100644 index 0000000000..4d8d8e9adc --- /dev/null +++ b/src/soc/qualcomm/ipq40xx/clock.c @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2012 - 2013 The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <delay.h> +#include <soc/clock.h> +#include <types.h> + +/** + * uart_pll_vote_clk_enable - enables PLL8 + */ +void uart_pll_vote_clk_enable(unsigned int clk_dummy) +{ + setbits_le32(BB_PLL_ENA_SC0_REG, BIT(8)); + + if (!clk_dummy) + while ((read32(PLL_LOCK_DET_STATUS_REG) & BIT(8)) == 0) + ; +} + +/** + * uart_set_rate_mnd - configures divider M and D values + * + * Sets the M, D parameters of the divider to generate the GSBI UART + * apps clock. + */ +static void uart_set_rate_mnd(unsigned int gsbi_port, unsigned int m, + unsigned int n) +{ + /* Assert MND reset. */ + setbits_le32(GSBIn_UART_APPS_NS_REG(gsbi_port), BIT(7)); + /* Program M and D values. */ + write32(GSBIn_UART_APPS_MD_REG(gsbi_port), MD16(m, n)); + /* Deassert MND reset. */ + clrbits_le32(GSBIn_UART_APPS_NS_REG(gsbi_port), BIT(7)); +} + +/** + * uart_branch_clk_enable_reg - enables branch clock + * + * Enables branch clock for GSBI UART port. + */ +static void uart_branch_clk_enable_reg(unsigned int gsbi_port) +{ + setbits_le32(GSBIn_UART_APPS_NS_REG(gsbi_port), BIT(9)); +} + +/** + * uart_local_clock_enable - configures N value and enables root clocks + * + * Sets the N parameter of the divider and enables root clock and + * branch clocks for GSBI UART port. + */ +static void uart_local_clock_enable(unsigned int gsbi_port, unsigned int n, + unsigned int m) +{ + unsigned int reg_val, uart_ns_val; + void *const reg = (void *)GSBIn_UART_APPS_NS_REG(gsbi_port); + + /* + * Program the NS register, if applicable. NS registers are not + * set in the set_rate path because power can be saved by deferring + * the selection of a clocked source until the clock is enabled. + */ + reg_val = read32(reg); // REG(0x29D4+(0x20*((n)-1))) + reg_val &= ~(Uart_clk_ns_mask); + uart_ns_val = NS(BIT_POS_31, BIT_POS_16, n, m, 5, 4, 3, 1, 2, 0, 3); + reg_val |= (uart_ns_val & Uart_clk_ns_mask); + write32(reg, reg_val); + + /* enable MNCNTR_EN */ + reg_val = read32(reg); + reg_val |= BIT(8); + write32(reg, reg_val); + + /* set source to PLL8 running @384MHz */ + reg_val = read32(reg); + reg_val |= 0x3; + write32(reg, reg_val); + + /* Enable root. */ + reg_val |= Uart_en_mask; + write32(reg, reg_val); + uart_branch_clk_enable_reg(gsbi_port); +} + +/** + * uart_set_gsbi_clk - enables HCLK for UART GSBI port + */ +static void uart_set_gsbi_clk(unsigned int gsbi_port) +{ + setbits_le32(GSBIn_HCLK_CTL_REG(gsbi_port), BIT(4)); +} + +/** + * uart_clock_config - configures UART clocks + * + * Configures GSBI UART dividers, enable root and branch clocks. + */ +void uart_clock_config(unsigned int gsbi_port, unsigned int m, + unsigned int n, unsigned int d, unsigned int clk_dummy) +{ + uart_set_rate_mnd(gsbi_port, m, d); + uart_pll_vote_clk_enable(clk_dummy); + uart_local_clock_enable(gsbi_port, n, m); + uart_set_gsbi_clk(gsbi_port); +} + +/** + * nand_clock_config - configure NAND controller clocks + * + * Enable clocks to EBI2. Must be invoked before touching EBI2 + * registers. + */ +void nand_clock_config(void) +{ + write32(EBI2_CLK_CTL_REG, + CLK_BRANCH_ENA(1) | ALWAYS_ON_CLK_BRANCH_ENA(1)); + + /* Wait for clock to stabilize. */ + udelay(10); +} + +/** + * usb_clock_config - configure USB controller clocks and reset the controller + */ +void usb_clock_config(void) +{ + /* Magic clock initialization numbers, nobody knows how they work... */ + write32(USB30_MASTER_CLK_CTL_REG, 0x10); + write32(USB30_1_MASTER_CLK_CTL_REG, 0x10); + write32(USB30_MASTER_CLK_MD, 0x500DF); + write32(USB30_MASTER_CLK_NS, 0xE40942); + write32(USB30_MOC_UTMI_CLK_MD, 0x100D7); + write32(USB30_MOC_UTMI_CLK_NS, 0xD80942); + write32(USB30_MOC_UTMI_CLK_CTL, 0x10); + write32(USB30_1_MOC_UTMI_CLK_CTL, 0x10); + + write32(USB30_RESET, + 1 << 5 | /* assert port2 HS PHY async reset */ + 1 << 4 | /* assert master async reset */ + 1 << 3 | /* assert sleep async reset */ + 1 << 2 | /* assert MOC UTMI async reset */ + 1 << 1 | /* assert power-on async reset */ + 1 << 0); /* assert PHY async reset */ + udelay(5); + write32(USB30_RESET, 0); /* deassert all USB resets again */ +} diff --git a/src/soc/qualcomm/ipq40xx/gpio.c b/src/soc/qualcomm/ipq40xx/gpio.c new file mode 100644 index 0000000000..47c0fcdaa7 --- /dev/null +++ b/src/soc/qualcomm/ipq40xx/gpio.c @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <arch/io.h> +#include <gpio.h> +#include <soc/iomap.h> + +/******************************************************* +Function description: check for invalid GPIO # +Arguments : +gpio_t gpio - Gpio number + +Return : GPIO Valid(0)/Invalid(1) +*******************************************************/ + +static inline int gpio_not_valid(gpio_t gpio) +{ + return (gpio > GPIO_MAX_NUM); +} + + +/******************************************************* +Function description: configure GPIO functinality +Arguments : +gpio_t gpio - Gpio number +unsigned func - Functionality number +unsigned pull - pull up/down, no pull range(0-3) +unsigned drvstr - range (0 - 7)-> (2- 16)MA steps of 2 +unsigned enable - 0 Disable, 1 - Enable. + +Return : None +*******************************************************/ + + +void gpio_tlmm_config_set(gpio_t gpio, unsigned func, + unsigned pull, unsigned drvstr, + unsigned enable) +{ + unsigned val = 0; + + if (gpio_not_valid(gpio)) + return; + + val |= (pull & GPIO_CFG_PULL_MASK) << GPIO_CFG_PULL_SHIFT; + val |= (func & GPIO_CFG_FUNC_MASK) << GPIO_CFG_FUNC_SHIFT; + val |= (drvstr & GPIO_CFG_DRV_MASK) << GPIO_CFG_DRV_SHIFT; + val |= (enable & GPIO_CFG_OE_MASK) << GPIO_CFG_OE_SHIFT; + + write32(GPIO_CONFIG_ADDR(gpio), val); +} + +/******************************************************* +Function description: Get GPIO configuration +Arguments : +gpio_t gpio - Gpio number +unsigned *func - Functionality number +unsigned *pull - pull up/down, no pull range(0-3) +unsigned *drvstr - range (0 - 7)-> (2- 16)MA steps of 2 +unsigned *enable - 0 - Disable, 1- Enable. + +Return : None +*******************************************************/ + + +void gpio_tlmm_config_get(gpio_t gpio, unsigned *func, + unsigned *pull, unsigned *drvstr, + unsigned *enable) +{ + unsigned val; + void *addr = GPIO_CONFIG_ADDR(gpio); + + if (gpio_not_valid(gpio)) + return; + + val = read32(addr); + + *pull = (val >> GPIO_CFG_PULL_SHIFT) & GPIO_CFG_PULL_MASK; + *func = (val >> GPIO_CFG_FUNC_SHIFT) & GPIO_CFG_FUNC_MASK; + *drvstr = (val >> GPIO_CFG_DRV_SHIFT) & GPIO_CFG_DRV_MASK; + *enable = (val >> GPIO_CFG_OE_SHIFT) & GPIO_CFG_OE_MASK; +} + +/******************************************************* +Function description: get GPIO IO functinality details +Arguments : +gpio_t gpio - Gpio number +unsigned *in - Value of GPIO input +unsigned *out - Value of GPIO output + +Return : None +*******************************************************/ +int gpio_get(gpio_t gpio) +{ + if (gpio_not_valid(gpio)) + return -1; + + + return (read32(GPIO_IN_OUT_ADDR(gpio)) >> GPIO_IO_IN_SHIFT) & + GPIO_IO_IN_MASK; +} + +void gpio_set(gpio_t gpio, int value) +{ + if (gpio_not_valid(gpio)) + return; + + write32(GPIO_IN_OUT_ADDR(gpio), (value & 1) << GPIO_IO_OUT_SHIFT); +} + +void gpio_input_pulldown(gpio_t gpio) +{ + gpio_tlmm_config_set(gpio, GPIO_FUNC_DISABLE, + GPIO_PULL_DOWN, GPIO_2MA, GPIO_DISABLE); +} + +void gpio_input_pullup(gpio_t gpio) +{ + gpio_tlmm_config_set(gpio, GPIO_FUNC_DISABLE, + GPIO_PULL_UP, GPIO_2MA, GPIO_DISABLE); +} + +void gpio_input(gpio_t gpio) +{ + gpio_tlmm_config_set(gpio, GPIO_FUNC_DISABLE, + GPIO_NO_PULL, GPIO_2MA, GPIO_DISABLE); +} diff --git a/src/soc/qualcomm/ipq40xx/gsbi.c b/src/soc/qualcomm/ipq40xx/gsbi.c new file mode 100644 index 0000000000..98c4edd084 --- /dev/null +++ b/src/soc/qualcomm/ipq40xx/gsbi.c @@ -0,0 +1,109 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2014 - 2015 The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <arch/io.h> +#include <soc/iomap.h> +#include <soc/gsbi.h> +#include <console/console.h> + +static inline void *gsbi_ctl_reg_addr(gsbi_id_t gsbi_id) +{ + switch (gsbi_id) { + case GSBI_ID_1: + return GSBI1_CTL_REG; + case GSBI_ID_2: + return GSBI2_CTL_REG; + case GSBI_ID_3: + return GSBI3_CTL_REG; + case GSBI_ID_4: + return GSBI4_CTL_REG; + case GSBI_ID_5: + return GSBI5_CTL_REG; + case GSBI_ID_6: + return GSBI6_CTL_REG; + case GSBI_ID_7: + return GSBI7_CTL_REG; + default: + printk(BIOS_ERR, "Unsupported GSBI%d\n", gsbi_id); + return 0; + } +} + +gsbi_return_t gsbi_init(gsbi_id_t gsbi_id, gsbi_protocol_t protocol) +{ + unsigned reg_val; + unsigned m = 1; + unsigned n = 4; + unsigned pre_div = 4; + unsigned src = 3; + unsigned mnctr_mode = 2; + void *gsbi_ctl = gsbi_ctl_reg_addr(gsbi_id); + + if (!gsbi_ctl) + return GSBI_ID_ERROR; + + write32(GSBI_HCLK_CTL(gsbi_id), + (1 << GSBI_HCLK_CTL_GATE_ENA) | + (1 << GSBI_HCLK_CTL_BRANCH_ENA)); + + if (gsbi_init_board(gsbi_id)) + return GSBI_UNSUPPORTED; + + write32(GSBI_QUP_APSS_NS_REG(gsbi_id), 0); + write32(GSBI_QUP_APSS_MD_REG(gsbi_id), 0); + + reg_val = ((m & GSBI_QUP_APPS_M_MASK) << GSBI_QUP_APPS_M_SHFT) | + ((~n & GSBI_QUP_APPS_D_MASK) << GSBI_QUP_APPS_D_SHFT); + write32(GSBI_QUP_APSS_MD_REG(gsbi_id), reg_val); + + reg_val = (((~(n - m)) & GSBI_QUP_APPS_N_MASK) << + GSBI_QUP_APPS_N_SHFT) | + ((mnctr_mode & GSBI_QUP_APPS_MNCTR_MODE_MSK) << + GSBI_QUP_APPS_MNCTR_MODE_SFT) | + (((pre_div - 1) & GSBI_QUP_APPS_PRE_DIV_MSK) << + GSBI_QUP_APPS_PRE_DIV_SFT) | + (src & GSBI_QUP_APPS_SRC_SEL_MSK); + write32(GSBI_QUP_APSS_NS_REG(gsbi_id), reg_val); + + reg_val |= (1 << GSBI_QUP_APPS_ROOT_ENA_SFT) | + (1 << GSBI_QUP_APPS_MNCTR_EN_SFT); + write32(GSBI_QUP_APSS_NS_REG(gsbi_id), reg_val); + + reg_val |= (1 << GSBI_QUP_APPS_BRANCH_ENA_SFT); + write32(GSBI_QUP_APSS_NS_REG(gsbi_id), reg_val); + + /*Select i2c protocol*/ + write32(gsbi_ctl, + ((GSBI_CTL_PROTO_I2C & GSBI_CTL_PROTO_CODE_MSK) + << GSBI_CTL_PROTO_CODE_SFT)); + + return GSBI_SUCCESS; +} diff --git a/src/soc/qualcomm/ipq40xx/i2c.c b/src/soc/qualcomm/ipq40xx/i2c.c new file mode 100644 index 0000000000..f84b8e25c1 --- /dev/null +++ b/src/soc/qualcomm/ipq40xx/i2c.c @@ -0,0 +1,170 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2014 - 2015 The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <arch/io.h> +#include <assert.h> +#include <console/console.h> +#include <delay.h> +#include <device/i2c.h> +#include <stdlib.h> +#include <string.h> +#include <soc/gsbi.h> +#include <soc/qup.h> + +static qup_config_t gsbi1_qup_config = { + QUP_MINICORE_I2C_MASTER, + 100000, + 24000000, + QUP_MODE_FIFO, + 0 +}; + +static qup_config_t gsbi4_qup_config = { + QUP_MINICORE_I2C_MASTER, + 100000, + 24000000, + QUP_MODE_FIFO, + 0 +}; + +static qup_config_t gsbi7_qup_config = { + QUP_MINICORE_I2C_MASTER, + 100000, + 24000000, + QUP_MODE_FIFO, + 0 +}; + +static int i2c_read(uint32_t gsbi_id, uint8_t slave, + uint8_t *data, int data_len) +{ + qup_data_t obj; + qup_return_t qup_ret = 0; + + memset(&obj, 0, sizeof(obj)); + obj.protocol = QUP_MINICORE_I2C_MASTER; + obj.p.iic.addr = slave; + obj.p.iic.data_len = data_len; + obj.p.iic.data = data; + qup_ret = qup_recv_data(gsbi_id, &obj); + + if (QUP_SUCCESS != qup_ret) + return 1; + else + return 0; +} + +static int i2c_write(uint32_t gsbi_id, uint8_t slave, + uint8_t *data, int data_len, uint8_t stop_seq) +{ + qup_data_t obj; + qup_return_t qup_ret = 0; + + memset(&obj, 0, sizeof(obj)); + obj.protocol = QUP_MINICORE_I2C_MASTER; + obj.p.iic.addr = slave; + obj.p.iic.data_len = data_len; + obj.p.iic.data = data; + qup_ret = qup_send_data(gsbi_id, &obj, stop_seq); + + if (QUP_SUCCESS != qup_ret) + return 1; + else + return 0; +} + +static int i2c_init(unsigned bus) +{ + unsigned gsbi_id = bus; + qup_config_t *qup_config; + + switch (gsbi_id) { + case GSBI_ID_1: + qup_config = &gsbi1_qup_config; + break; + case GSBI_ID_4: + qup_config = &gsbi4_qup_config; + break; + case GSBI_ID_7: + qup_config = &gsbi7_qup_config; + break; + default: + printk(BIOS_ERR, "QUP configuration not defind for GSBI%d.\n", + gsbi_id); + return 1; + } + + if (qup_config->initialized) + return 0; + + if (gsbi_init(gsbi_id, GSBI_PROTO_I2C_ONLY)) { + printk(BIOS_ERR, "failed to initialize gsbi\n"); + return 1; + } + + if (qup_init(gsbi_id, qup_config)) { + printk(BIOS_ERR, "failed to initialize qup\n"); + return 1; + } + + if (qup_reset_i2c_master_status(gsbi_id)) { + printk(BIOS_ERR, "failed to reset i2c master status\n"); + return 1; + } + + qup_config->initialized = 1; + return 0; +} + +int platform_i2c_transfer(unsigned bus, struct i2c_seg *segments, int seg_count) +{ + struct i2c_seg *seg = segments; + int ret = 0; + + if (i2c_init(bus)) + return 1; + + while (!ret && seg_count--) { + if (seg->read) + ret = i2c_read(bus, seg->chip, seg->buf, seg->len); + else + ret = i2c_write(bus, seg->chip, seg->buf, seg->len, + (seg_count ? 0 : 1)); + seg++; + } + + if (ret) { + qup_set_state(bus, QUP_STATE_RESET); + return 1; + } + + return 0; +} diff --git a/src/soc/qualcomm/ipq40xx/include/soc/cdp.h b/src/soc/qualcomm/ipq40xx/include/soc/cdp.h new file mode 100644 index 0000000000..57c679e12e --- /dev/null +++ b/src/soc/qualcomm/ipq40xx/include/soc/cdp.h @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2012 The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#ifndef _IPQ40XX_CDP_H_ +#define _IPQ40XX_CDP_H_ + +#include <types.h> + +unsigned smem_get_board_machtype(void); + +typedef enum { + PHY_INTERFACE_MODE_MII, + PHY_INTERFACE_MODE_GMII, + PHY_INTERFACE_MODE_SGMII, + PHY_INTERFACE_MODE_QSGMII, + PHY_INTERFACE_MODE_TBI, + PHY_INTERFACE_MODE_RMII, + PHY_INTERFACE_MODE_RGMII, + PHY_INTERFACE_MODE_RGMII_ID, + PHY_INTERFACE_MODE_RGMII_RXID, + PHY_INTERFACE_MODE_RGMII_TXID, + PHY_INTERFACE_MODE_RTBI, + PHY_INTERFACE_MODE_XGMII, + PHY_INTERFACE_MODE_NONE /* Must be last */ +} phy_interface_t; + +typedef struct { + unsigned int gpio; + unsigned int func; + unsigned int dir; + unsigned int pull; + unsigned int drvstr; + unsigned int enable; +} gpio_func_data_t; + +typedef struct { + unsigned int m_value; + unsigned int n_value; + unsigned int d_value; +} uart_clk_mnd_t; + +/* SPI Mode */ + +typedef enum { + NOR_SPI_MODE_0, + NOR_SPI_MODE_1, + NOR_SPI_MODE_2, + NOR_SPI_MODE_3, +} spi_mode; + +/* SPI GSBI Bus number */ + +typedef enum { + GSBI_BUS_5 = 0, + GSBI_BUS_6, + GSBI_BUS_7, +} spi_gsbi_bus_num; + +/* SPI Chip selects */ + +typedef enum { + SPI_CS_0 , + SPI_CS_1, + SPI_CS_2, + SPI_CS_3, +} spi_cs; + +/* Flash Types */ + +typedef enum { + ONLY_NAND, + ONLY_NOR, + NAND_NOR, + NOR_MMC, +} flash_desc; + +#define NO_OF_DBG_UART_GPIOS 2 + +#define SPI_NOR_FLASH_VENDOR_MICRON 0x1 +#define SPI_NOR_FLASH_VENDOR_SPANSION 0x2 + +/* SPI parameters */ + +typedef struct { + spi_mode mode; + spi_gsbi_bus_num bus_number; + spi_cs chip_select; + int vendor; +} spinorflash_params_t; + +typedef struct { + unsigned count; + uint8_t addr[7]; +} ipq_gmac_phy_addr_t; + +typedef struct { + unsigned base; + int unit; + unsigned is_macsec; + unsigned mac_pwr0; + unsigned mac_pwr1; + unsigned mac_conn_to_phy; + phy_interface_t phy; + ipq_gmac_phy_addr_t phy_addr; +} ipq_gmac_board_cfg_t; + +#define IPQ_GMAC_NMACS 4 + +enum gale_board_id { + BOARD_ID_PROTO_0 = 0, + BOARD_ID_PROTO_0_2 = 1, + BOARD_ID_WHIRLWIND = 2, + BOARD_ID_WHIRLWIND_SP5 = 3, + BOARD_ID_PROTO_0_2_NAND = 26, +}; + +/* Board specific parameters */ +typedef struct { +#if 0 + unsigned int gmac_gpio_count; + gpio_func_data_t *gmac_gpio; + ipq_gmac_board_cfg_t gmac_cfg[IPQ_GMAC_NMACS]; + flash_desc flashdesc; + spinorflash_params_t flash_param; +#endif +} __attribute__ ((__packed__)) board_ipq40xx_params_t; + +extern board_ipq40xx_params_t *gboard_param; + +#if 0 +static inline int gmac_cfg_is_valid(ipq_gmac_board_cfg_t *cfg) +{ + /* + * 'cfg' is valid if and only if + * unit number is non-negative and less than IPQ_GMAC_NMACS. + * 'cfg' pointer lies within the array range of + * board_ipq40xx_params_t->gmac_cfg[] + */ + return ((cfg >= &gboard_param->gmac_cfg[0]) && + (cfg < &gboard_param->gmac_cfg[IPQ_GMAC_NMACS]) && + (cfg->unit >= 0) && (cfg->unit < IPQ_GMAC_NMACS)); +} +#endif + +unsigned int get_board_index(unsigned machid); +void ipq_configure_gpio(const gpio_func_data_t *gpio, unsigned count); + +void board_nand_init(void); + +#endif /* _IPQ40XX_CDP_H_ */ diff --git a/src/soc/qualcomm/ipq40xx/include/soc/clock.h b/src/soc/qualcomm/ipq40xx/include/soc/clock.h new file mode 100644 index 0000000000..51cc228c71 --- /dev/null +++ b/src/soc/qualcomm/ipq40xx/include/soc/clock.h @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2012-2013 The Linux Foundation. All rights reserved. + * Source : APQ8064 LK Boot + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __IPQ40XX_CLOCK_H_ +#define __IPQ40XX_CLOCK_H_ + +#include <soc/iomap.h> + +/* UART clock @ 7.3728 MHz */ +#define UART_DM_CLK_RX_TX_BIT_RATE 0xCC + +/* UART specific definitions */ + +#define Uart_ns_val NS(BIT_POS_31, BIT_POS_16, N_VALUE, M_VALUE, \ + 5, 4, 3, 1, 2, 0, 3) +#define Uart_clk_ns_mask (BM(BIT_POS_31, BIT_POS_16) | \ + BM(BIT_POS_6, BIT_POS_0)) +#define Uart_mnd_en_mask (BIT(8) * !!(625)) +#define Uart_en_mask BIT(11) +#define MD16(m, n) (BVAL(BIT_POS_31, BIT_POS_16, m) | \ + BVAL(BIT_POS_15, BIT_POS_0, ~(n))) +#define Uart_ns_val_rumi NS(BIT_POS_31, BIT_POS_16, N_VALUE, M_VALUE, \ + 5, 4, 3, 1, 2, 0, 0) +#define GSBIn_UART_APPS_MD_REG(n) REG(0x29D0+(0x20*((n)-1))) +#define GSBIn_UART_APPS_NS_REG(n) REG(0x29D4+(0x20*((n)-1))) +#define GSBIn_HCLK_CTL_REG(n) REG(0x29C0+(0x20*((n)-1))) +#define BB_PLL_ENA_SC0_REG REG(0x34C0) +#define BB_PLL8_STATUS_REG REG(0x3158) +#define REG(off) ((void *)(MSM_CLK_CTL_BASE + (off))) +#define PLL8_STATUS_BIT 16 + +#define PLL_LOCK_DET_STATUS_REG REG(0x03420) +#define SFAB_AHB_S3_FCLK_CTL_REG REG(0x0216C) +#define CFPB_CLK_NS_REG REG(0x0264C) +#define CFPB0_HCLK_CTL_REG REG(0x02650) +#define SFAB_CFPB_S_HCLK_CTL_REG REG(0x026C0) +#define CFPB_SPLITTER_HCLK_CTL_REG REG(0x026E0) +#define EBI2_CLK_CTL_REG REG(0x03B00) + +#define USB30_MASTER_CLK_CTL_REG REG(0x3b24) +#define USB30_MASTER_CLK_MD REG(0x3b28) +#define USB30_MASTER_CLK_NS REG(0x3b2c) +#define USB30_1_MASTER_CLK_CTL_REG REG(0x3b34) +#define USB30_MOC_UTMI_CLK_MD REG(0x3b40) +#define USB30_MOC_UTMI_CLK_NS REG(0x3b44) +#define USB30_MOC_UTMI_CLK_CTL REG(0x3b48) +#define USB30_1_MOC_UTMI_CLK_CTL REG(0x3b4c) +#define USB30_RESET REG(0x3b50) + +#define ALWAYS_ON_CLK_BRANCH_ENA(i) ((i) << 8) + +#define CLK_BRANCH_ENA_MASK 0x00000010 +#define CLK_BRANCH_ENA_ENABLE 0x00000010 +#define CLK_BRANCH_ENA_DISABLE 0x00000000 +#define CLK_BRANCH_ENA(i) ((i) << 4) + +/* Register: CFPB_CLK_NS */ +#define CLK_DIV_MASK 0x00000003 +#define CLK_DIV_DIV_1 0x00000000 +#define CLK_DIV_DIV_2 0x00000001 +#define CLK_DIV_DIV_3 0x00000002 +#define CLK_DIV_DIV_4 0x00000003 +#define CLK_DIV(i) ((i) << 0) + +#define MN_MODE_DUAL_EDGE 0x2 +#define BIT_POS_31 31 +#define BIT_POS_16 16 +#define BIT_POS_6 6 +#define BIT_POS_0 0 +#define BIT_POS_15 15 + +#define BM(m, l) (((((unsigned int)-1) << (31-m)) >> (31-m+l)) << l) +#define BVAL(m, l, val) (((val) << l) & BM(m, l)) + +/* MD Registers */ +#define MD4(m_lsb, m, n_lsb, n) \ + (BVAL((m_lsb+3), m_lsb, m) | BVAL((n_lsb+3), n_lsb, ~(n))) + +#define MD8(m_lsb, m, n_lsb, n) \ + (BVAL((m_lsb+7), m_lsb, m) | BVAL((n_lsb+7), n_lsb, ~(n))) + +/* NS Registers */ +#define NS(n_msb, n_lsb, n, m, mde_lsb, d_msb, d_lsb, d, s_msb, s_lsb, s) \ + (BVAL(n_msb, n_lsb, ~(n-m)) \ + | (BVAL((mde_lsb+1), mde_lsb, MN_MODE_DUAL_EDGE) * !!(n)) \ + | BVAL(d_msb, d_lsb, (d-1)) | BVAL(s_msb, s_lsb, s)) + +#define NS_MM(n_msb, n_lsb, n, m, d_msb, d_lsb, d, s_msb, s_lsb, s) \ + (BVAL(n_msb, n_lsb, ~(n-m)) | BVAL(d_msb, d_lsb, (d-1)) \ + | BVAL(s_msb, s_lsb, s)) + +#define NS_DIVSRC(d_msb , d_lsb, d, s_msb, s_lsb, s) \ + (BVAL(d_msb, d_lsb, (d-1)) | BVAL(s_msb, s_lsb, s)) + +#define NS_DIV(d_msb , d_lsb, d) \ + BVAL(d_msb, d_lsb, (d-1)) + +#define NS_SRC_SEL(s_msb, s_lsb, s) \ + BVAL(s_msb, s_lsb, s) + +#define GMAC_AHB_RESET 0x903E24 + +#define SRC_SEL_PLL0 (0x2 << 0) +#define MNCNTR_MODE_DUAL_EDGE (0x2 << 5) +#define MNCNTR_ENABLE (0x1 << 8) +#define MNCNTR_RST_ACTIVE (0x1 << 7) +#define N_VAL 15 + +#define GMAC_CORE_RESET(n) \ + ((void *)(0x903CBC + ((n) * 0x20))) + +#define GMACSEC_CORE_RESET(n) \ + ((void *)(0x903E28 + ((n - 1) * 4))) + +#define GMAC_COREn_CLCK_SRC_CTL(N) \ + (0x00900000 + (0x3CA0 + (32*(N-1)))) + +#define GMAC_COREn_CLCK_SRC0_MD(N) \ + (0x00900000 + (0x3CA4 + (32*(N-1)))) + +#define GMAC_COREn_CLCK_SRC1_MD(N) \ + (0x00900000 + (0x3CA8 + (32*(N-1)))) + +#define GMAC_COREn_CLCK_SRC0_NS(N) \ + (0x00900000 + (0x3CAC + (32*(N-1)))) + +#define GMAC_COREn_CLCK_SRC1_NS(N) \ + (0x00900000 + (0x3CB0 + (32*(N-1)))) + +#define DISABLE_DUAL_MN8_SEL (0) +#define DISABLE_CLK_LOW_PWR (0 << 2) +#define GMAC_CORE_CLCK_ROOT_ENABLE (1 << 1) + +/* GMAC_COREn_CLK_SRC[0,1]_MD register bits (Assuming 133MHz) */ +#define GMAC_CORE_CLCK_M 0x32 +#define GMAC_CORE_CLCK_D 0 /* NOT(2*D) value */ +#define GMAC_CORE_CLCK_M_SHIFT 16 +#define GMAC_CORE_CLCK_D_SHIFT 0 +#define GMAC_CORE_CLCK_M_VAL \ + (GMAC_CORE_CLCK_M << GMAC_CORE_CLCK_M_SHIFT) +#define GMAC_CORE_CLCK_D_VAL \ + (GMAC_CORE_CLCK_D << GMAC_CORE_CLCK_D_SHIFT) + +/* GMAC_COREn_CLK_SRC[0,1]_NS register bits (Assuming 133MHz) */ +#define GMAC_CORE_CLCK_N 0x4 /* NOT(N-M) value, N=301 */ +#define GMAC_CORE_CLCK_N_SHIFT 16 +#define GMAC_CORE_CLCK_N_VAL \ + (GMAC_CORE_CLCK_N << GMAC_CORE_CLCK_N_SHIFT) +/* Enable M/N counter */ +#define GMAC_CORE_CLCK_MNCNTR_EN 0x00000100 +/* Activate reset for M/N counter */ +#define GMAC_CORE_CLCK_MNCNTR_RST 0x00000080 +/* M/N counter mode mask */ +#define GMAC_CORE_CLCK_MNCNTR_MODE_MASK 0x00000060 +#define GMAC_CORE_CLCK_MNCNTR_MODE_SHIFT 5 +/* M/N counter mode dual-edge */ +#define GMAC_CORE_CLCK_MNCNTR_MODE_DUAL \ + (2 << GMAC_CORE_CLCK_MNCNTR_MODE_SHIFT) +/* Pre divider select mask */ +#define GMAC_CORE_CLCK_PRE_DIV_SEL_MASK 0x00000018 +#define GMAC_CORE_CLCK_PRE_DIV_SEL_SHIFT 3 +/* Pre divider bypass */ +#define GMAC_CORE_CLCK_PRE_DIV_SEL_BYP \ + (0 << GMAC_CORE_CLCK_PRE_DIV_SEL_SHIFT) +/* clk source Mux select mask */ +#define GMAC_CORE_CLCK_SRC_SEL_MASK 0x00000007 +#define GMAC_CORE_CLCK_SRC_SEL_SHIFT 0 +/* output of clk source Mux is PLL0 */ +#define GMAC_CORE_CLCK_SRC_SEL_PLL0 \ + (2 << GMAC_CORE_CLCK_SRC_SEL_SHIFT) +#define GMAC_COREn_CLCK_CTL(N) \ + (0x00900000 + (0x3CB4 + (32*(N-1)))) + +#define GMAC_COREn_CLCK_INV_DISABLE (0 << 5) +#define GMAC_COREn_CLCK_BRANCH_ENA (1 << 4) + + +/* Uart specific clock settings */ + +void uart_pll_vote_clk_enable(unsigned int); +void uart_clock_config(unsigned int gsbi_port, unsigned int m, unsigned int n, + unsigned int d, unsigned int clk_dummy); +void nand_clock_config(void); +void usb_clock_config(void); +int audio_clock_config(unsigned frequency); + +#endif /* __PLATFORM_IPQ40XX_CLOCK_H_ */ diff --git a/src/soc/qualcomm/ipq40xx/include/soc/ebi2.h b/src/soc/qualcomm/ipq40xx/include/soc/ebi2.h new file mode 100644 index 0000000000..1cc04aefad --- /dev/null +++ b/src/soc/qualcomm/ipq40xx/include/soc/ebi2.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2012 The Linux Foundation. All rights reserved. + * + * Taken from U-Boot. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __SOC_QUALCOMM_IPQ40XX_EBI2_H_ +#define __SOC_QUALCOMM_IPQ40XX_EBI2_H_ + +#define EBI2CR_BASE (0x1A600000) + +struct ebi2cr_regs { + uint32_t chip_select_cfg0; /* 0x00000000 */ + uint32_t cfg; /* 0x00000004 */ + uint32_t hw_info; /* 0x00000008 */ + uint8_t reserved0[20]; + uint32_t lcd_cfg0; /* 0x00000020 */ + uint32_t lcd_cfg1; /* 0x00000024 */ + uint8_t reserved1[8]; + uint32_t arbiter_cfg; /* 0x00000030 */ + uint8_t reserved2[28]; + uint32_t debug_sel; /* 0x00000050 */ + uint32_t crc_cfg; /* 0x00000054 */ + uint32_t crc_reminder_cfg; /* 0x00000058 */ + uint32_t nand_adm_mux; /* 0x0000005C */ + uint32_t mutex_addr_offset; /* 0x00000060 */ + uint32_t misr_value; /* 0x00000064 */ + uint32_t clkon_cfg; /* 0x00000068 */ + uint32_t core_clkon_cfg; /* 0x0000006C */ +}; + +/* Register: EBI2_CHIP_SELECT_CFG0 */ +#define CS7_CFG_MASK 0x00001000 +#define CS7_CFG_DISABLE 0x00000000 +#define CS7_CFG_GENERAL_SRAM_MEMORY_INTERFACE 0x00001000 +#define CS7_CFG(i) ((i) << 12) + +#define CS6_CFG_MASK 0x00000800 +#define CS6_CFG_DISABLE 0x00000000 +#define CS6_CFG_GENERAL_SRAM_MEMORY_INTERFACE 0x00000800 +#define CS6_CFG(i) ((i) << 11) + +#define ETM_CS_CFG_MASK 0x00000400 +#define ETM_CS_CFG_DISABLE 0x00000000 +#define ETM_CS_CFG_GENERAL_SRAM_MEMORY_INTERFACE 0x00000400 +#define ETM_CS_CFG(i) ((i) << 10) + +#define CS5_CFG_MASK 0x00000300 +#define CS5_CFG_DISABLE 0x00000000 +#define CS5_CFG_LCD_DEVICE_CONNECTED 0x00000100 +#define CS5_CFG_LCD_DEVICE_CHIP_ENABLE 0x00000200 +#define CS5_CFG_GENERAL_SRAM_MEMORY_INTERFACE 0x00000300 +#define CS5_CFG(i) ((i) << 8) + +#define CS4_CFG_MASK 0x000000c0 +#define CS4_CFG_DISABLE 0x00000000 +#define CS4_CFG_LCD_DEVICE_CONNECTED 0x00000040 +#define CS4_CFG_GENERAL_SRAM_MEMORY_INTERFACE 0x000000C0 +#define CS4_CFG(i) ((i) << 6) + +#define CS3_CFG_MASK 0x00000020 +#define CS3_CFG_DISABLE 0x00000000 +#define CS3_CFG_GENERAL_SRAM_MEMORY_INTERFACE 0x00000020 +#define CS3_CFG(i) ((i) << 5) + +#define CS2_CFG_MASK 0x00000010 +#define CS2_CFG_DISABLE 0x00000000 +#define CS2_CFG_GENERAL_SRAM_MEMORY_INTERFACE 0x00000010 +#define CS2_CFG(i) ((i) << 4) + +#define CS1_CFG_MASK 0x0000000c +#define CS1_CFG_DISABLE 0x00000000 +#define CS1_CFG_SERIAL_FLASH_DEVICE 0x00000004 +#define CS1_CFG_GENERAL_SRAM_MEMORY_INTERFACE 0x00000008 +#define CS1_CFG(i) ((i) << 2) + +#define CS0_CFG_MASK 0x00000003 +#define CS0_CFG_DISABLE 0x00000000 +#define CS0_CFG_SERIAL_FLASH_DEVICE 0x00000001 +#define CS0_CFG_GENERAL_SRAM_MEMORY_INTERFACE 0x00000002 +#define CS0_CFG(i) ((i) << 0) + +#endif diff --git a/src/soc/qualcomm/ipq40xx/include/soc/gpio.h b/src/soc/qualcomm/ipq40xx/include/soc/gpio.h new file mode 100644 index 0000000000..6304f71757 --- /dev/null +++ b/src/soc/qualcomm/ipq40xx/include/soc/gpio.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2012 The Linux Foundation. All rights reserved. + * Source : APQ8064 LK Boot + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __SOC_QUALCOMM_IPQ40XX_GPIO_H_ +#define __SOC_QUALCOMM_IPQ40XX_GPIO_H_ + +#include <types.h> + +#define GPIO_FUNC_ENABLE 1 +#define GPIO_FUNC_DISABLE 0 +#define FUNC_SEL_1 1 +#define FUNC_SEL_3 3 +#define FUNC_SEL_GPIO 0 +#define GPIO_DRV_STR_10MA 0x4 +#define GPIO_DRV_STR_11MA 0x7 + +/* GPIO TLMM: Direction */ +#define GPIO_INPUT 0 +#define GPIO_OUTPUT 1 + +/* GPIO TLMM: Pullup/Pulldown */ +#define GPIO_NO_PULL 0 +#define GPIO_PULL_DOWN 1 +#define GPIO_KEEPER 2 +#define GPIO_PULL_UP 3 + +/* GPIO TLMM: Drive Strength */ +#define GPIO_2MA 0 +#define GPIO_4MA 1 +#define GPIO_6MA 2 +#define GPIO_8MA 3 +#define GPIO_10MA 4 +#define GPIO_12MA 5 +#define GPIO_14MA 6 +#define GPIO_16MA 7 + +/* GPIO TLMM: Status */ +#define GPIO_DISABLE 0 +#define GPIO_ENABLE 1 + +/* GPIO MAX Valid # */ +#define GPIO_MAX_NUM 68 + +/* GPIO TLMM: Mask */ +#define GPIO_CFG_PULL_MASK 0x3 +#define GPIO_CFG_FUNC_MASK 0xF +#define GPIO_CFG_DRV_MASK 0x7 +#define GPIO_CFG_OE_MASK 0x1 + +/* GPIO TLMM: Shift */ +#define GPIO_CFG_PULL_SHIFT 0 +#define GPIO_CFG_FUNC_SHIFT 2 +#define GPIO_CFG_DRV_SHIFT 6 +#define GPIO_CFG_OE_SHIFT 9 + +/* GPIO IO: Mask */ +#define GPIO_IO_IN_MASK 0x1 +#define GPIO_IO_OUT_MASK 0x1 + +/* GPIO IO: Shift */ +#define GPIO_IO_IN_SHIFT 0 +#define GPIO_IO_OUT_SHIFT 1 + +typedef u32 gpio_t; + +void gpio_tlmm_config_set(gpio_t gpio, unsigned int func, + unsigned int pull, unsigned int drvstr, + unsigned int enable); + +void gpio_tlmm_config_get(gpio_t gpio, unsigned int *func, + unsigned int *pull, unsigned int *drvstr, + unsigned int *enable); + +void gpio_io_config_set(gpio_t gpio, unsigned int out); + +/* Keep this to maintain backwards compatibility with the vendor API. */ +static inline void gpio_tlmm_config(unsigned int gpio, unsigned int func, + unsigned int dir, unsigned int pull, + unsigned int drvstr, unsigned int enable) +{ + gpio_tlmm_config_set(gpio, func, pull, drvstr, enable); +} +#endif // __SOC_QUALCOMM_IPQ40XX_GPIO_H_ diff --git a/src/soc/qualcomm/ipq40xx/include/soc/gsbi.h b/src/soc/qualcomm/ipq40xx/include/soc/gsbi.h new file mode 100644 index 0000000000..f2c375df0f --- /dev/null +++ b/src/soc/qualcomm/ipq40xx/include/soc/gsbi.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2011-2012 The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#ifndef __GSBI_H_ +#define __GSBI_H_ + +/* GSBI Registers */ +#define GSBI_CTRL_REG(base) ((base) + 0x0) + +#define GSBI_CTRL_REG_PROTOCOL_CODE_S 4 +#define GSBI_PROTOCOL_CODE_I2C 0x2 +#define GSBI_PROTOCOL_CODE_SPI 0x3 +#define GSBI_PROTOCOL_CODE_UART_FLOW 0x4 +#define GSBI_PROTOCOL_CODE_I2C_UART 0x6 + +#define GSBI_HCLK_CTL_S 4 +#define GSBI_HCLK_CTL_CLK_ENA 0x1 + +typedef enum { + GSBI_ID_1 = 1, + GSBI_ID_2, + GSBI_ID_3, + GSBI_ID_4, + GSBI_ID_5, + GSBI_ID_6, + GSBI_ID_7, +} gsbi_id_t; + +typedef enum { + GSBI_SUCCESS = 0, + GSBI_ID_ERROR, + GSBI_ERROR, + GSBI_UNSUPPORTED +} gsbi_return_t; + +typedef enum { + GSBI_PROTO_I2C_UIM = 1, + GSBI_PROTO_I2C_ONLY, + GSBI_PROTO_SPI_ONLY, + GSBI_PROTO_UART_FLOW_CTL, + GSBI_PROTO_UIM, + GSBI_PROTO_I2C_UART, +} gsbi_protocol_t; + +gsbi_return_t gsbi_init(gsbi_id_t gsbi_id, gsbi_protocol_t protocol); +int gsbi_init_board(gsbi_id_t gsbi_id); + +#endif diff --git a/src/soc/qualcomm/ipq40xx/include/soc/iomap.h b/src/soc/qualcomm/ipq40xx/include/soc/iomap.h new file mode 100644 index 0000000000..543356dcbc --- /dev/null +++ b/src/soc/qualcomm/ipq40xx/include/soc/iomap.h @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2012 - 2013, 2015 The Linux Foundation. All rights reserved. + * + * Copyright (c) 2008, Google Inc. + * All rights reserved. + * + * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google, Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef __SOC_QUALCOMM_IPQ40XX_IOMAP_H_ +#define __SOC_QUALCOMM_IPQ40XX_IOMAP_H_ + +#include <arch/io.h> +#include <soc/cdp.h> + +/* Typecast to allow integers being passed as address + This needs to be included because vendor code is not compliant with our + macros for read/write. Hence, special macros for readl_i and writel_i are + included to do this in one place for all occurrences in vendor code + */ +#define readl_i(a) read32((const void *)(a)) +#define writel_i(v,a) write32((void *)a, v) +#define clrsetbits_le32_i(addr, clear, set) \ + clrsetbits_le32(((void *)(addr)), (clear), (set)) + +#define MSM_CLK_CTL_BASE ((void *)0x00900000) + +#define MSM_TMR_BASE ((void *)0x0200A000) +#define MSM_GPT_BASE (MSM_TMR_BASE + 0x04) +#define MSM_DGT_BASE (MSM_TMR_BASE + 0x24) + +#define GPT_REG(off) (MSM_GPT_BASE + (off)) +#define DGT_REG(off) (MSM_DGT_BASE + (off)) + +#define APCS_WDT0_EN (MSM_TMR_BASE + 0x0040) +#define APCS_WDT0_RST (MSM_TMR_BASE + 0x0038) +#define APCS_WDT0_BARK_TIME (MSM_TMR_BASE + 0x004C) +#define APCS_WDT0_BITE_TIME (MSM_TMR_BASE + 0x005C) + +#define APCS_WDT0_CPU0_WDOG_EXPIRED_ENABLE (MSM_CLK_CTL_BASE + 0x3820) + +#define GPT_MATCH_VAL GPT_REG(0x0000) +#define GPT_COUNT_VAL GPT_REG(0x0004) +#define GPT_ENABLE GPT_REG(0x0008) +#define GPT_CLEAR GPT_REG(0x000C) + +#define GPT1_MATCH_VAL GPT_REG(0x00010) +#define GPT1_COUNT_VAL GPT_REG(0x00014) +#define GPT1_ENABLE GPT_REG(0x00018) +#define GPT1_CLEAR GPT_REG(0x0001C) + +#define DGT_MATCH_VAL DGT_REG(0x0000) +#define DGT_COUNT_VAL DGT_REG(0x0004) +#define DGT_ENABLE DGT_REG(0x0008) +#define DGT_CLEAR DGT_REG(0x000C) +#define DGT_CLK_CTL DGT_REG(0x0010) + +/* RPM interface constants */ +#define RPM_INT ((void *)0x63020) +#define RPM_INT_ACK ((void *)0x63060) +#define RPM_SIGNAL_COOKIE ((void *)0x47C20) +#define RPM_SIGNAL_ENTRY ((void *)0x47C24) +#define RPM_FW_MAGIC_NUM 0x4D505242 + +#define TLMM_BASE_ADDR ((void *)0x00800000) +#define GPIO_CONFIG_ADDR(x) (TLMM_BASE_ADDR + 0x1000 + (x)*0x10) +#define GPIO_IN_OUT_ADDR(x) (GPIO_CONFIG_ADDR(x) + 4) + +/* Yes, this is not a typo... host2 is actually mapped before host1. */ +#define USB_HOST2_XHCI_BASE 0x10000000 +#define USB_HOST2_DWC3_BASE 0x1000C100 +#define USB_HOST2_PHY_BASE 0x100F8800 +#define USB_HOST1_XHCI_BASE 0x11000000 +#define USB_HOST1_DWC3_BASE 0x1100C100 +#define USB_HOST1_PHY_BASE 0x110F8800 + +#define GSBI_4 4 +#define UART1_DM_BASE 0x12450000 +#define UART_GSBI1_BASE 0x12440000 +#define UART2_DM_BASE 0x12490000 +#define UART_GSBI2_BASE 0x12480000 +#define UART4_DM_BASE 0x16340000 +#define UART_GSBI4_BASE 0x16300000 + +#define UART2_DM_BASE 0x12490000 +#define UART_GSBI2_BASE 0x12480000 + +#define GSBI1_BASE ((void *)0x12440000) +#define GSBI2_BASE ((void *)0x12480000) +#define GSBI3_BASE ((void *)0x16200000) +#define GSBI4_BASE ((void *)0x16300000) +#define GSBI5_BASE ((void *)0x1A200000) +#define GSBI6_BASE ((void *)0x16500000) +#define GSBI7_BASE ((void *)0x16600000) + +#define GSBI1_CTL_REG (GSBI1_BASE + (0x0)) +#define GSBI2_CTL_REG (GSBI2_BASE + (0x0)) +#define GSBI3_CTL_REG (GSBI3_BASE + (0x0)) +#define GSBI4_CTL_REG (GSBI4_BASE + (0x0)) +#define GSBI5_CTL_REG (GSBI5_BASE + (0x0)) +#define GSBI6_CTL_REG (GSBI6_BASE + (0x0)) +#define GSBI7_CTL_REG (GSBI7_BASE + (0x0)) + +#define GSBI_QUP1_BASE (GSBI1_BASE + 0x20000) +#define GSBI_QUP2_BASE (GSBI2_BASE + 0x20000) +#define GSBI_QUP3_BASE (GSBI3_BASE + 0x80000) +#define GSBI_QUP4_BASE (GSBI4_BASE + 0x80000) +#define GSBI_QUP5_BASE (GSBI5_BASE + 0x80000) +#define GSBI_QUP6_BASE (GSBI6_BASE + 0x80000) +#define GSBI_QUP7_BASE (GSBI7_BASE + 0x80000) + +#define GSBI_CTL_PROTO_I2C 2 +#define GSBI_CTL_PROTO_CODE_SFT 4 +#define GSBI_CTL_PROTO_CODE_MSK 0x7 +#define GSBI_HCLK_CTL_GATE_ENA 6 +#define GSBI_HCLK_CTL_BRANCH_ENA 4 +#define GSBI_QUP_APPS_M_SHFT 16 +#define GSBI_QUP_APPS_M_MASK 0xFF +#define GSBI_QUP_APPS_D_SHFT 0 +#define GSBI_QUP_APPS_D_MASK 0xFF +#define GSBI_QUP_APPS_N_SHFT 16 +#define GSBI_QUP_APPS_N_MASK 0xFF +#define GSBI_QUP_APPS_ROOT_ENA_SFT 11 +#define GSBI_QUP_APPS_BRANCH_ENA_SFT 9 +#define GSBI_QUP_APPS_MNCTR_EN_SFT 8 +#define GSBI_QUP_APPS_MNCTR_MODE_MSK 0x3 +#define GSBI_QUP_APPS_MNCTR_MODE_SFT 5 +#define GSBI_QUP_APPS_PRE_DIV_MSK 0x3 +#define GSBI_QUP_APPS_PRE_DIV_SFT 3 +#define GSBI_QUP_APPS_SRC_SEL_MSK 0x7 + + +#define GSBI_QUP_APSS_MD_REG(gsbi_n) ((MSM_CLK_CTL_BASE + 0x29c8) + \ + (32*(gsbi_n-1))) +#define GSBI_QUP_APSS_NS_REG(gsbi_n) ((MSM_CLK_CTL_BASE + 0x29cc) + \ + (32*(gsbi_n-1))) +#define GSBI_HCLK_CTL(n) ((MSM_CLK_CTL_BASE + 0x29C0) + \ + (32*(n-1))) +#endif // __SOC_QUALCOMM_IPQ40XX_IOMAP_H_ diff --git a/src/soc/qualcomm/ipq40xx/include/soc/ipq_timer.h b/src/soc/qualcomm/ipq40xx/include/soc/ipq_timer.h new file mode 100644 index 0000000000..0d0f9d2942 --- /dev/null +++ b/src/soc/qualcomm/ipq40xx/include/soc/ipq_timer.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define TIMER_LOAD_VAL 0x21 + +#define GPT_ENABLE_CLR_ON_MATCH_EN 2 +#define GPT_ENABLE_EN 1 +#define DGT_ENABLE_CLR_ON_MATCH_EN 2 +#define DGT_ENABLE_EN 1 + +#define SPSS_TIMER_STATUS_DGT_EN (1 << 0) diff --git a/src/soc/qualcomm/ipq40xx/include/soc/ipq_uart.h b/src/soc/qualcomm/ipq40xx/include/soc/ipq_uart.h new file mode 100644 index 0000000000..25a06bff93 --- /dev/null +++ b/src/soc/qualcomm/ipq40xx/include/soc/ipq_uart.h @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2012 The Linux Foundation. All rights reserved.* + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __UART_DM_H__ +#define __UART_DM_H__ + +#define PERIPH_BLK_BLSP 0 + +#define MSM_BOOT_UART_DM_EXTR_BITS(value, start_pos, end_pos) \ + ((value << (32 - end_pos)) >> (32 - (end_pos - start_pos))) + +extern void __udelay(unsigned long usec); + + +enum MSM_BOOT_UART_DM_PARITY_MODE { + MSM_BOOT_UART_DM_NO_PARITY, + MSM_BOOT_UART_DM_ODD_PARITY, + MSM_BOOT_UART_DM_EVEN_PARITY, + MSM_BOOT_UART_DM_SPACE_PARITY +}; + +/* UART Stop Bit Length */ +enum MSM_BOOT_UART_DM_STOP_BIT_LEN { + MSM_BOOT_UART_DM_SBL_9_16, + MSM_BOOT_UART_DM_SBL_1, + MSM_BOOT_UART_DM_SBL_1_9_16, + MSM_BOOT_UART_DM_SBL_2 +}; + +/* UART Bits per Char */ +enum MSM_BOOT_UART_DM_BITS_PER_CHAR { + MSM_BOOT_UART_DM_5_BPS, + MSM_BOOT_UART_DM_6_BPS, + MSM_BOOT_UART_DM_7_BPS, + MSM_BOOT_UART_DM_8_BPS +}; + +/* 8-N-1 Configuration */ +#define MSM_BOOT_UART_DM_8_N_1_MODE (MSM_BOOT_UART_DM_NO_PARITY | \ + (MSM_BOOT_UART_DM_SBL_1 << 2) | \ + (MSM_BOOT_UART_DM_8_BPS << 4)) + +/* UART_DM Registers */ + +/* UART Operational Mode Register */ +#define MSM_BOOT_UART_DM_MR1(base) ((base) + 0x00) +#define MSM_BOOT_UART_DM_MR2(base) ((base) + 0x04) +#define MSM_BOOT_UART_DM_RXBRK_ZERO_CHAR_OFF (1 << 8) +#define MSM_BOOT_UART_DM_LOOPBACK (1 << 7) + +/* UART Clock Selection Register */ +#if PERIPH_BLK_BLSP +#define MSM_BOOT_UART_DM_CSR(base) ((base) + 0xA0) +#else +#define MSM_BOOT_UART_DM_CSR(base) ((base) + 0x08) +#endif + +/* UART DM TX FIFO Registers - 4 */ +#if PERIPH_BLK_BLSP +#define MSM_BOOT_UART_DM_TF(base, x) ((base) + 0x100+(4*(x))) +#else +#define MSM_BOOT_UART_DM_TF(base, x) ((base) + 0x70+(4*(x))) +#endif + +/* UART Command Register */ +#if PERIPH_BLK_BLSP +#define MSM_BOOT_UART_DM_CR(base) ((base) + 0xA8) +#else +#define MSM_BOOT_UART_DM_CR(base) ((base) + 0x10) +#endif +#define MSM_BOOT_UART_DM_CR_RX_ENABLE (1 << 0) +#define MSM_BOOT_UART_DM_CR_RX_DISABLE (1 << 1) +#define MSM_BOOT_UART_DM_CR_TX_ENABLE (1 << 2) +#define MSM_BOOT_UART_DM_CR_TX_DISABLE (1 << 3) + +/* UART Channel Command */ +#define MSM_BOOT_UART_DM_CR_CH_CMD_LSB(x) ((x & 0x0f) << 4) +#define MSM_BOOT_UART_DM_CR_CH_CMD_MSB(x) ((x >> 4) << 11) +#define MSM_BOOT_UART_DM_CR_CH_CMD(x) \ + (MSM_BOOT_UART_DM_CR_CH_CMD_LSB(x) | MSM_BOOT_UART_DM_CR_CH_CMD_MSB(x)) +#define MSM_BOOT_UART_DM_CMD_NULL MSM_BOOT_UART_DM_CR_CH_CMD(0) +#define MSM_BOOT_UART_DM_CMD_RESET_RX MSM_BOOT_UART_DM_CR_CH_CMD(1) +#define MSM_BOOT_UART_DM_CMD_RESET_TX MSM_BOOT_UART_DM_CR_CH_CMD(2) +#define MSM_BOOT_UART_DM_CMD_RESET_ERR_STAT MSM_BOOT_UART_DM_CR_CH_CMD(3) +#define MSM_BOOT_UART_DM_CMD_RES_BRK_CHG_INT MSM_BOOT_UART_DM_CR_CH_CMD(4) +#define MSM_BOOT_UART_DM_CMD_START_BRK MSM_BOOT_UART_DM_CR_CH_CMD(5) +#define MSM_BOOT_UART_DM_CMD_STOP_BRK MSM_BOOT_UART_DM_CR_CH_CMD(6) +#define MSM_BOOT_UART_DM_CMD_RES_CTS_N MSM_BOOT_UART_DM_CR_CH_CMD(7) +#define MSM_BOOT_UART_DM_CMD_RES_STALE_INT MSM_BOOT_UART_DM_CR_CH_CMD(8) +#define MSM_BOOT_UART_DM_CMD_PACKET_MODE MSM_BOOT_UART_DM_CR_CH_CMD(9) +#define MSM_BOOT_UART_DM_CMD_MODE_RESET MSM_BOOT_UART_DM_CR_CH_CMD(C) +#define MSM_BOOT_UART_DM_CMD_SET_RFR_N MSM_BOOT_UART_DM_CR_CH_CMD(D) +#define MSM_BOOT_UART_DM_CMD_RES_RFR_N MSM_BOOT_UART_DM_CR_CH_CMD(E) +#define MSM_BOOT_UART_DM_CMD_RES_TX_ERR MSM_BOOT_UART_DM_CR_CH_CMD(10) +#define MSM_BOOT_UART_DM_CMD_CLR_TX_DONE MSM_BOOT_UART_DM_CR_CH_CMD(11) +#define MSM_BOOT_UART_DM_CMD_RES_BRKSTRT_INT MSM_BOOT_UART_DM_CR_CH_CMD(12) +#define MSM_BOOT_UART_DM_CMD_RES_BRKEND_INT MSM_BOOT_UART_DM_CR_CH_CMD(13) +#define MSM_BOOT_UART_DM_CMD_RES_PER_FRM_INT MSM_BOOT_UART_DM_CR_CH_CMD(14) + +/*UART General Command */ +#define MSM_BOOT_UART_DM_CR_GENERAL_CMD(x) ((x) << 8) + +#define MSM_BOOT_UART_DM_GCMD_NULL MSM_BOOT_UART_DM_CR_GENERAL_CMD(0) +#define MSM_BOOT_UART_DM_GCMD_CR_PROT_EN MSM_BOOT_UART_DM_CR_GENERAL_CMD(1) +#define MSM_BOOT_UART_DM_GCMD_CR_PROT_DIS MSM_BOOT_UART_DM_CR_GENERAL_CMD(2) +#define MSM_BOOT_UART_DM_GCMD_RES_TX_RDY_INT MSM_BOOT_UART_DM_CR_GENERAL_CMD(3) +#define MSM_BOOT_UART_DM_GCMD_SW_FORCE_STALE MSM_BOOT_UART_DM_CR_GENERAL_CMD(4) +#define MSM_BOOT_UART_DM_GCMD_ENA_STALE_EVT MSM_BOOT_UART_DM_CR_GENERAL_CMD(5) +#define MSM_BOOT_UART_DM_GCMD_DIS_STALE_EVT MSM_BOOT_UART_DM_CR_GENERAL_CMD(6) + +/* UART Interrupt Mask Register */ +#if PERIPH_BLK_BLSP +#define MSM_BOOT_UART_DM_IMR(base) ((base) + 0xB0) +#else +#define MSM_BOOT_UART_DM_IMR(base) ((base) + 0x14) +#endif + +#define MSM_BOOT_UART_DM_TXLEV (1 << 0) +#define MSM_BOOT_UART_DM_RXHUNT (1 << 1) +#define MSM_BOOT_UART_DM_RXBRK_CHNG (1 << 2) +#define MSM_BOOT_UART_DM_RXSTALE (1 << 3) +#define MSM_BOOT_UART_DM_RXLEV (1 << 4) +#define MSM_BOOT_UART_DM_DELTA_CTS (1 << 5) +#define MSM_BOOT_UART_DM_CURRENT_CTS (1 << 6) +#define MSM_BOOT_UART_DM_TX_READY (1 << 7) +#define MSM_BOOT_UART_DM_TX_ERROR (1 << 8) +#define MSM_BOOT_UART_DM_TX_DONE (1 << 9) +#define MSM_BOOT_UART_DM_RXBREAK_START (1 << 10) +#define MSM_BOOT_UART_DM_RXBREAK_END (1 << 11) +#define MSM_BOOT_UART_DM_PAR_FRAME_ERR_IRQ (1 << 12) + +#define MSM_BOOT_UART_DM_IMR_ENABLED (MSM_BOOT_UART_DM_TX_READY | \ + MSM_BOOT_UART_DM_TXLEV | \ + MSM_BOOT_UART_DM_RXSTALE) + +/* UART Interrupt Programming Register */ +#define MSM_BOOT_UART_DM_IPR(base) ((base) + 0x18) +#define MSM_BOOT_UART_DM_STALE_TIMEOUT_LSB 0x0f +#define MSM_BOOT_UART_DM_STALE_TIMEOUT_MSB 0 /* Not used currently */ + +/* UART Transmit/Receive FIFO Watermark Register */ +#define MSM_BOOT_UART_DM_TFWR(base) ((base) + 0x1C) +/* Interrupt is generated when FIFO level is less than or equal to this value */ +#define MSM_BOOT_UART_DM_TFW_VALUE 0 + +#define MSM_BOOT_UART_DM_RFWR(base) ((base) + 0x20) +/*Interrupt generated when no of words in RX FIFO is greater than this value */ +#define MSM_BOOT_UART_DM_RFW_VALUE 0 + +/* UART Hunt Character Register */ +#define MSM_BOOT_UART_DM_HCR(base) ((base) + 0x24) + +/* Used for RX transfer initialization */ +#define MSM_BOOT_UART_DM_DMRX(base) ((base) + 0x34) + +/* Default DMRX value - any value bigger than FIFO size would be fine */ +#define MSM_BOOT_UART_DM_DMRX_DEF_VALUE 0x220 + +/* Register to enable IRDA function */ +#if PERIPH_BLK_BLSP +#define MSM_BOOT_UART_DM_IRDA(base) ((base) + 0xB8) +#else +#define MSM_BOOT_UART_DM_IRDA(base) ((base) + 0x38) +#endif + +/* UART Data Mover Enable Register */ +#define MSM_BOOT_UART_DM_DMEN(base) ((base) + 0x3C) + +/* Number of characters for Transmission */ +#define MSM_BOOT_UART_DM_NO_CHARS_FOR_TX(base) ((base) + 0x040) + +/* UART RX FIFO Base Address */ +#define MSM_BOOT_UART_DM_BADR(base) ((base) + 0x44) + +/* UART Status Register */ +#if PERIPH_BLK_BLSP +#define MSM_BOOT_UART_DM_SR(base) ((base) + 0x0A4) +#else +#define MSM_BOOT_UART_DM_SR(base) ((base) + 0x008) +#endif +#define MSM_BOOT_UART_DM_SR_RXRDY (1 << 0) +#define MSM_BOOT_UART_DM_SR_RXFULL (1 << 1) +#define MSM_BOOT_UART_DM_SR_TXRDY (1 << 2) +#define MSM_BOOT_UART_DM_SR_TXEMT (1 << 3) +#define MSM_BOOT_UART_DM_SR_UART_OVERRUN (1 << 4) +#define MSM_BOOT_UART_DM_SR_PAR_FRAME_ERR (1 << 5) +#define MSM_BOOT_UART_DM_RX_BREAK (1 << 6) +#define MSM_BOOT_UART_DM_HUNT_CHAR (1 << 7) +#define MSM_BOOT_UART_DM_RX_BRK_START_LAST (1 << 8) + +/* UART Receive FIFO Registers - 4 in numbers */ +#if PERIPH_BLK_BLSP +#define MSM_BOOT_UART_DM_RF(base, x) ((base) + 0x140 + (4*(x))) +#else +#define MSM_BOOT_UART_DM_RF(base, x) ((base) + 0x70 + (4*(x))) +#endif + +/* UART Masked Interrupt Status Register */ +#if PERIPH_BLK_BLSP +#define MSM_BOOT_UART_DM_MISR(base) ((base) + 0xAC) +#else +#define MSM_BOOT_UART_DM_MISR(base) ((base) + 0x10) +#endif + +/* UART Interrupt Status Register */ +#if PERIPH_BLK_BLSP +#define MSM_BOOT_UART_DM_ISR(base) ((base) + 0xB4) +#else +#define MSM_BOOT_UART_DM_ISR(base) ((base) + 0x14) +#endif + +/* Number of characters received since the end of last RX transfer */ +#if PERIPH_BLK_BLSP +#define MSM_BOOT_UART_DM_RX_TOTAL_SNAP(base) ((base) + 0xBC) +#else +#define MSM_BOOT_UART_DM_RX_TOTAL_SNAP(base) ((base) + 0x38) +#endif + +/* UART TX FIFO Status Register */ +#define MSM_BOOT_UART_DM_TXFS(base) ((base) + 0x4C) +#define MSM_BOOT_UART_DM_TXFS_STATE_LSB(x) MSM_BOOT_UART_DM_EXTR_BITS(x, 0, 6) +#define MSM_BOOT_UART_DM_TXFS_STATE_MSB(x) \ + MSM_BOOT_UART_DM_EXTR_BITS(x, 14, 31) +#define MSM_BOOT_UART_DM_TXFS_BUF_STATE(x) MSM_BOOT_UART_DM_EXTR_BITS(x, 7, 9) +#define MSM_BOOT_UART_DM_TXFS_ASYNC_STATE(x) \ + MSM_BOOT_UART_DM_EXTR_BITS(x, 10, 13) + +/* UART RX FIFO Status Register */ +#define MSM_BOOT_UART_DM_RXFS(base) ((base) + 0x50) +#define MSM_BOOT_UART_DM_RXFS_STATE_LSB(x) MSM_BOOT_UART_DM_EXTR_BITS(x, 0, 6) +#define MSM_BOOT_UART_DM_RXFS_STATE_MSB(x) \ + MSM_BOOT_UART_DM_EXTR_BITS(x, 14, 31) +#define MSM_BOOT_UART_DM_RXFS_BUF_STATE(x) MSM_BOOT_UART_DM_EXTR_BITS(x, 7, 9) +#define MSM_BOOT_UART_DM_RXFS_ASYNC_STATE(x) \ + MSM_BOOT_UART_DM_EXTR_BITS(x, 10, 13) + +/* Macros for Common Errors */ +#define MSM_BOOT_UART_DM_E_SUCCESS 0 +#define MSM_BOOT_UART_DM_E_FAILURE 1 +#define MSM_BOOT_UART_DM_E_TIMEOUT 2 +#define MSM_BOOT_UART_DM_E_INVAL 3 +#define MSM_BOOT_UART_DM_E_MALLOC_FAIL 4 +#define MSM_BOOT_UART_DM_E_RX_NOT_READY 5 + +void ipq40xx_uart_init(void); + +#endif /* __UART_DM_H__ */ diff --git a/src/soc/qualcomm/ipq40xx/include/soc/lcc-reg.h b/src/soc/qualcomm/ipq40xx/include/soc/lcc-reg.h new file mode 100644 index 0000000000..9cf375840f --- /dev/null +++ b/src/soc/qualcomm/ipq40xx/include/soc/lcc-reg.h @@ -0,0 +1,341 @@ +/* + * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __DRIVERS_CLOCK_IPQ40XX_LCC_REG_H__ +#define __DRIVERS_CLOCK_IPQ40XX_LCC_REG_H__ + +#define MSM_GCC_BASE 0x00900000 +#define MSM_LPASS_LCC_BASE 0x28000000 + +/* GCC APCS Configuration/Control */ + +#define GCC_PLL_APCS_REG 0x34C0 + +#define GCC_PLL_APCS_PLL4_MASK 0x10 +#define GCC_PLL_APCS_PLL4_SHIFT 4 +#define GCC_PLL_APCS_PLL4_ENABLE (1 << GCC_PLL_APCS_PLL4_SHIFT) + +/* LCC PLL0 Configuration/Control */ + +#define LCC_PLL0_MODE_REG 0x00 +#define LCC_PLL0_L_REG 0x04 +#define LCC_PLL0_M_REG 0x08 +#define LCC_PLL0_N_REG 0x0C +#define LCC_PLL0_CFG_REG 0x14 +#define LCC_PLL0_STAT_REG 0x18 + +#define LCC_PLL0_MODE_FSM_RESET_MASK 0x200000 +#define LCC_PLL0_MODE_FSM_RESET_SHIFT 21 +#define LCC_PLL0_MODE_FSM_RESET_ASSERT (1 << LCC_PLL0_MODE_FSM_RESET_SHIFT) + +#define LCC_PLL0_MODE_FSM_VOTE_MASK 0x100000 +#define LCC_PLL0_MODE_FSM_VOTE_SHIFT 20 +#define LCC_PLL0_MODE_FSM_VOTE_ENABLE (1 << LCC_PLL0_MODE_FSM_VOTE_SHIFT) + +#define LCC_PLL0_MODE_BIAS_CNT_MASK 0xFC000 +#define LCC_PLL0_MODE_BIAS_CNT_SHIFT 14 + +#define LCC_PLL0_MODE_LOCK_CNT_MASK 0x3F00 +#define LCC_PLL0_MODE_LOCK_CNT_SHIFT 8 + +#define LCC_PLL0_MODE_XO_SEL_MASK 0x30 +#define LCC_PLL0_MODE_XO_SEL_SHIFT 4 +#define LCC_PLL0_MODE_XO_SEL_PXO (0 << LCC_PLL0_MODE_XO_SEL_SHIFT) +#define LCC_PLL0_MODE_XO_SEL_MXO (1 << LCC_PLL0_MODE_XO_SEL_SHIFT) +#define LCC_PLL0_MODE_XO_SEL_CXO (2 << LCC_PLL0_MODE_XO_SEL_SHIFT) + +#define LCC_PLL0_MODE_TEST_MASK 0x8 +#define LCC_PLL0_MODE_TEST_SHIFT 3 +#define LCC_PLL0_MODE_TEST_ENABLE (1 << LCC_PLL0_MODE_TEST_SHIFT) + +#define LCC_PLL0_MODE_RESET_MASK 0x4 +#define LCC_PLL0_MODE_RESET_SHIFT 2 +#define LCC_PLL0_MODE_RESET_DEASSERT (1 << LCC_PLL0_MODE_RESET_SHIFT) + +#define LCC_PLL0_MODE_BYPASS_MASK 0x2 +#define LCC_PLL0_MODE_BYPASS_SHIFT 1 +#define LCC_PLL0_MODE_BYPASS_DISABLE (1 << LCC_PLL0_MODE_BYPASS_SHIFT) + +#define LCC_PLL0_MODE_OUTPUT_MASK 0x1 +#define LCC_PLL0_MODE_OUTPUT_SHIFT 0 +#define LCC_PLL0_MODE_OUTPUT_ENABLE (1 << LCC_PLL0_MODE_OUTPUT_SHIFT) + +#define LCC_PLL0_L_MASK 0x3FF +#define LCC_PLL0_L_SHIFT 0 + +#define LCC_PLL0_M_MASK 0x7FFFF +#define LCC_PLL0_M_SHIFT 0 + +#define LCC_PLL0_N_MASK 0x7FFFF +#define LCC_PLL0_N_SHIFT 0 + +#define LCC_PLL0_CFG_LV_MAIN_MASK 0x800000 +#define LCC_PLL0_CFG_LV_MAIN_SHIFT 23 +#define LCC_PLL0_CFG_LV_MAIN_ENABLE (1 << LCC_PLL0_CFG_LV_MAIN_SHIFT) + +#define LCC_PLL0_CFG_FRAC_MASK 0x400000 +#define LCC_PLL0_CFG_FRAC_SHIFT 22 +#define LCC_PLL0_CFG_FRAC_ENABLE (1 << LCC_PLL0_CFG_FRAC_SHIFT) + +#define LCC_PLL0_CFG_POSTDIV_MASK 0x300000 +#define LCC_PLL0_CFG_POSTDIV_SHIFT 20 +#define LCC_PLL0_CFG_POSTDIV_DIV1 (0 << LCC_PLL0_CFG_POSTDIV_SHIFT) +#define LCC_PLL0_CFG_POSTDIV_DIV2 (1 << LCC_PLL0_CFG_POSTDIV_SHIFT) +#define LCC_PLL0_CFG_POSTDIV_DIV4 (2 << LCC_PLL0_CFG_POSTDIV_SHIFT) + +#define LCC_PLL0_CFG_PREDIV_MASK 0x80000 +#define LCC_PLL0_CFG_PREDIV_SHIFT 19 +#define LCC_PLL0_CFG_PREDIV_DIV1 (0 << LCC_PLL0_CFG_PREDIV_SHIFT) +#define LCC_PLL0_CFG_PREDIV_DIV2 (1 << LCC_PLL0_CFG_PREDIV_SHIFT) + +#define LCC_PLL0_CFG_VCO_SEL_MASK 0x30000 +#define LCC_PLL0_CFG_VCO_SEL_SHIFT 16 +#define LCC_PLL0_CFG_VCO_SEL_LOW (0 << LCC_PLL0_CFG_VCO_SEL_SHIFT) +#define LCC_PLL0_CFG_VCO_SEL_MED (1 << LCC_PLL0_CFG_VCO_SEL_SHIFT) +#define LCC_PLL0_CFG_VCO_SEL_HIGH (2 << LCC_PLL0_CFG_VCO_SEL_SHIFT) + +#define LCC_PLL0_STAT_ACTIVE_MASK 0x10000 +#define LCC_PLL0_STAT_ACTIVE_SHIFT 16 +#define LCC_PLL0_STAT_ACTIVE_SET (1 << LCC_PLL0_STAT_ACTIVE_SHIFT) + +#define LCC_PLL0_STAT_NOCLK_MASK 0x1 +#define LCC_PLL0_STAT_NOCLK_SHIFT 0 +#define LCC_PLL0_STAT_NOCLK_SET (1 << LCC_PLL0_STAT_NOCLK_SHIFT) + +/* LCC AHBIX Configuration/Control */ + +#define LCC_AHBIX_NS_REG 0x38 +#define LCC_AHBIX_MD_REG 0x3C +#define LCC_AHBIX_STAT_REG 0x44 + +#define LCC_AHBIX_NS_N_VAL_MASK 0xFF000000 +#define LCC_AHBIX_NS_N_VAL_SHIFT 24 + +#define LCC_AHBIX_NS_CRC_MASK 0x800 +#define LCC_AHBIX_NS_CRC_SHIFT 11 +#define LCC_AHBIX_NS_CRC_ENABLE (1 << LCC_AHBIX_NS_CRC_SHIFT) + +#define LCC_AHBIX_NS_GFM_SEL_MASK 0x400 +#define LCC_AHBIX_NS_GFM_SEL_SHIFT 10 +#define LCC_AHBIX_NS_GFM_SEL_PXO (0 << LCC_AHBIX_NS_GFM_SEL_SHIFT) +#define LCC_AHBIX_NS_GFM_SEL_MNC (1 << LCC_AHBIX_NS_GFM_SEL_SHIFT) + +#define LCC_AHBIX_NS_MNC_CLK_MASK 0x200 +#define LCC_AHBIX_NS_MNC_CLK_SHIFT 9 +#define LCC_AHBIX_NS_MNC_CLK_ENABLE (1 << LCC_AHBIX_NS_MNC_CLK_SHIFT) + +#define LCC_AHBIX_NS_MNC_MASK 0x100 +#define LCC_AHBIX_NS_MNC_SHIFT 8 +#define LCC_AHBIX_NS_MNC_ENABLE (1 << LCC_AHBIX_NS_MNC_SHIFT) + +#define LCC_AHBIX_NS_MNC_RESET_MASK 0x80 +#define LCC_AHBIX_NS_MNC_RESET_SHIFT 7 +#define LCC_AHBIX_NS_MNC_RESET_ASSERT (1 << LCC_AHBIX_NS_MNC_RESET_SHIFT) + +#define LCC_AHBIX_NS_MNC_MODE_MASK 0x60 +#define LCC_AHBIX_NS_MNC_MODE_SHIFT 5 +#define LCC_AHBIX_NS_MNC_MODE_BYPASS (0 << LCC_AHBIX_NS_MNC_MODE_SHIFT) +#define LCC_AHBIX_NS_MNC_MODE_SWALLOW (1 << LCC_AHBIX_NS_MNC_MODE_SHIFT) +#define LCC_AHBIX_NS_MNC_MODE_DUAL (2 << LCC_AHBIX_NS_MNC_MODE_SHIFT) +#define LCC_AHBIX_NS_MNC_MODE_SINGLE (3 << LCC_AHBIX_NS_MNC_MODE_SHIFT) + +#define LCC_AHBIX_NS_PREDIV_MASK 0x18 +#define LCC_AHBIX_NS_PREDIV_SHIFT 3 +#define LCC_AHBIX_NS_PREDIV_BYPASS (0 << LCC_AHBIX_NS_PREDIV_SHIFT) +#define LCC_AHBIX_NS_PREDIV_DIV2 (1 << LCC_AHBIX_NS_PREDIV_SHIFT) +#define LCC_AHBIX_NS_PREDIV_DIV4 (3 << LCC_AHBIX_NS_PREDIV_SHIFT) + +#define LCC_AHBIX_NS_MN_SRC_MASK 0x7 +#define LCC_AHBIX_NS_MN_SRC_SHIFT 0 +#define LCC_AHBIX_NS_MN_SRC_PXO (0 << LCC_AHBIX_NS_MN_SRC_SHIFT) +#define LCC_AHBIX_NS_MN_SRC_CXO (1 << LCC_AHBIX_NS_MN_SRC_SHIFT) +#define LCC_AHBIX_NS_MN_SRC_LPA (2 << LCC_AHBIX_NS_MN_SRC_SHIFT) +#define LCC_AHBIX_NS_MN_SRC_SEC (3 << LCC_AHBIX_NS_MN_SRC_SHIFT) +#define LCC_AHBIX_NS_MN_SRC_CTEST (6 << LCC_AHBIX_NS_MN_SRC_SHIFT) +#define LCC_AHBIX_NS_MN_SRC_PTEST (7 << LCC_AHBIX_NS_MN_SRC_SHIFT) + +#define LCC_AHBIX_MD_M_VAL_MASK 0xFF00 +#define LCC_AHBIX_MD_M_VAL_SHIFT 8 + +#define LCC_AHBIX_MD_NOT_2D_VAL_MASK 0xFF +#define LCC_AHBIX_MD_NOT_2D_VAL_SHIFT 0 + +#define LCC_AHBIX_STAT_AHB_CLK_MASK 0x400 +#define LCC_AHBIX_STAT_AHB_CLK_SHIFT 10 +#define LCC_AHBIX_STAT_AHB_CLK_ON (1 << LCC_AHBIX_STAT_AHB_CLK_SHIFT) + +#define LCC_AHBIX_STAT_AIF_CLK_MASK 0x200 +#define LCC_AHBIX_STAT_AIF_CLK_SHIFT 9 +#define LCC_AHBIX_STAT_AIF_CLK_ON (1 << LCC_AHBIX_STAT_AIF_CLK_SHIFT) + +#define LCC_AHBIX_STAT_FAB2_CLK_MASK 0x40 +#define LCC_AHBIX_STAT_FAB2_CLK_SHIFT 6 +#define LCC_AHBIX_STAT_FAB2_CLK_ON (1 << LCC_AHBIX_STAT_FAB2_CLK_SHIFT) + +#define LCC_AHBIX_STAT_2FAB_CLK_MASK 0x20 +#define LCC_AHBIX_STAT_2FAB_CLK_SHIFT 5 +#define LCC_AHBIX_STAT_2FAB_CLK_ON (1 << LCC_AHBIX_STAT_2FAB_CLK_SHIFT) + +/* LCC MI2S Configuration/Control */ + +#define LCC_MI2S_NS_REG 0x48 +#define LCC_MI2S_MD_REG 0x4C +#define LCC_MI2S_STAT_REG 0x50 + +#define LCC_MI2S_NS_N_VAL_MASK 0xFF000000 +#define LCC_MI2S_NS_N_VAL_SHIFT 24 + +#define LCC_MI2S_NS_RESET_MASK 0x80000 +#define LCC_MI2S_NS_RESET_SHIFT 19 +#define LCC_MI2S_NS_RESET_ASSERT (1 << LCC_MI2S_NS_RESET_SHIFT) + +#define LCC_MI2S_NS_OSR_INV_MASK 0x40000 +#define LCC_MI2S_NS_OSR_INV_SHIFT 18 +#define LCC_MI2S_NS_OSR_INV_ENABLE (1 << LCC_MI2S_NS_OSR_INV_SHIFT) + +#define LCC_MI2S_NS_OSR_CXC_MASK 0x20000 +#define LCC_MI2S_NS_OSR_CXC_SHIFT 17 +#define LCC_MI2S_NS_OSR_CXC_ENABLE (1 << LCC_MI2S_NS_OSR_CXC_SHIFT) + +#define LCC_MI2S_NS_BIT_INV_MASK 0x10000 +#define LCC_MI2S_NS_BIT_INV_SHIFT 16 +#define LCC_MI2S_NS_BIT_INV_ENABLE (1 << LCC_MI2S_NS_BIT_INV_SHIFT) + +#define LCC_MI2S_NS_BIT_CXC_MASK 0x8000 +#define LCC_MI2S_NS_BIT_CXC_SHIFT 15 +#define LCC_MI2S_NS_BIT_CXC_ENABLE (1 << LCC_MI2S_NS_BIT_CXC_SHIFT) + +#define LCC_MI2S_NS_BIT_SRC_MASK 0x4000 +#define LCC_MI2S_NS_BIT_SRC_SHIFT 14 +#define LCC_MI2S_NS_BIT_SRC_MASTER (0 << LCC_MI2S_NS_BIT_SRC_SHIFT) +#define LCC_MI2S_NS_BIT_SRC_SLAVE (1 << LCC_MI2S_NS_BIT_SRC_SHIFT) + +#define LCC_MI2S_NS_BIT_DIV_MASK 0x3C00 +#define LCC_MI2S_NS_BIT_DIV_SHIFT 10 +#define LCC_MI2S_NS_BIT_DIV_BYPASS (0 << LCC_MI2S_NS_BIT_DIV_SHIFT) +#define LCC_MI2S_NS_BIT_DIV_DIV2 (1 << LCC_MI2S_NS_BIT_DIV_SHIFT) +#define LCC_MI2S_NS_BIT_DIV_DIV3 (2 << LCC_MI2S_NS_BIT_DIV_SHIFT) +#define LCC_MI2S_NS_BIT_DIV_DIV4 (3 << LCC_MI2S_NS_BIT_DIV_SHIFT) +#define LCC_MI2S_NS_BIT_DIV_DIV5 (4 << LCC_MI2S_NS_BIT_DIV_SHIFT) +#define LCC_MI2S_NS_BIT_DIV_DIV6 (5 << LCC_MI2S_NS_BIT_DIV_SHIFT) +#define LCC_MI2S_NS_BIT_DIV_DIV7 (6 << LCC_MI2S_NS_BIT_DIV_SHIFT) +#define LCC_MI2S_NS_BIT_DIV_DIV8 (7 << LCC_MI2S_NS_BIT_DIV_SHIFT) +#define LCC_MI2S_NS_BIT_DIV_DIV9 (8 << LCC_MI2S_NS_BIT_DIV_SHIFT) +#define LCC_MI2S_NS_BIT_DIV_DIV10 (9 << LCC_MI2S_NS_BIT_DIV_SHIFT) +#define LCC_MI2S_NS_BIT_DIV_DIV11 (10 << LCC_MI2S_NS_BIT_DIV_SHIFT) +#define LCC_MI2S_NS_BIT_DIV_DIV12 (11 << LCC_MI2S_NS_BIT_DIV_SHIFT) +#define LCC_MI2S_NS_BIT_DIV_DIV13 (12 << LCC_MI2S_NS_BIT_DIV_SHIFT) +#define LCC_MI2S_NS_BIT_DIV_DIV14 (13 << LCC_MI2S_NS_BIT_DIV_SHIFT) +#define LCC_MI2S_NS_BIT_DIV_DIV15 (14 << LCC_MI2S_NS_BIT_DIV_SHIFT) +#define LCC_MI2S_NS_BIT_DIV_DIV16 (15 << LCC_MI2S_NS_BIT_DIV_SHIFT) + +#define LCC_MI2S_NS_MNC_CLK_MASK 0x200 +#define LCC_MI2S_NS_MNC_CLK_SHIFT 9 +#define LCC_MI2S_NS_MNC_CLK_ENABLE (1 << LCC_MI2S_NS_MNC_CLK_SHIFT) + +#define LCC_MI2S_NS_MNC_MASK 0x100 +#define LCC_MI2S_NS_MNC_SHIFT 8 +#define LCC_MI2S_NS_MNC_ENABLE (1 << LCC_MI2S_NS_MNC_SHIFT) + +#define LCC_MI2S_NS_MNC_RESET_MASK 0x80 +#define LCC_MI2S_NS_MNC_RESET_SHIFT 7 +#define LCC_MI2S_NS_MNC_RESET_ASSERT (1 << LCC_MI2S_NS_MNC_RESET_SHIFT) + +#define LCC_MI2S_NS_MNC_MODE_MASK 0x60 +#define LCC_MI2S_NS_MNC_MODE_SHIFT 5 +#define LCC_MI2S_NS_MNC_MODE_BYPASS (0 << LCC_MI2S_NS_MNC_MODE_SHIFT) +#define LCC_MI2S_NS_MNC_MODE_SWALLOW (1 << LCC_MI2S_NS_MNC_MODE_SHIFT) +#define LCC_MI2S_NS_MNC_MODE_DUAL (2 << LCC_MI2S_NS_MNC_MODE_SHIFT) +#define LCC_MI2S_NS_MNC_MODE_SINGLE (3 << LCC_MI2S_NS_MNC_MODE_SHIFT) + +#define LCC_MI2S_NS_PREDIV_MASK 0x18 +#define LCC_MI2S_NS_PREDIV_SHIFT 3 +#define LCC_MI2S_NS_PREDIV_BYPASS (0 << LCC_MI2S_NS_PREDIV_SHIFT) +#define LCC_MI2S_NS_PREDIV_DIV2 (1 << LCC_MI2S_NS_PREDIV_SHIFT) +#define LCC_MI2S_NS_PREDIV_DIV4 (3 << LCC_MI2S_NS_PREDIV_SHIFT) + +#define LCC_MI2S_NS_MN_SRC_MASK 0x7 +#define LCC_MI2S_NS_MN_SRC_SHIFT 0 +#define LCC_MI2S_NS_MN_SRC_PXO (0 << LCC_MI2S_NS_MN_SRC_SHIFT) +#define LCC_MI2S_NS_MN_SRC_CXO (1 << LCC_MI2S_NS_MN_SRC_SHIFT) +#define LCC_MI2S_NS_MN_SRC_LPA (2 << LCC_MI2S_NS_MN_SRC_SHIFT) +#define LCC_MI2S_NS_MN_SRC_SEC (3 << LCC_MI2S_NS_MN_SRC_SHIFT) +#define LCC_MI2S_NS_MN_SRC_CTEST (6 << LCC_MI2S_NS_MN_SRC_SHIFT) +#define LCC_MI2S_NS_MN_SRC_PTEST (7 << LCC_MI2S_NS_MN_SRC_SHIFT) + +#define LCC_MI2S_MD_M_VAL_MASK 0xFF00 +#define LCC_MI2S_MD_M_VAL_SHIFT 8 + +#define LCC_MI2S_MD_NOT_2D_VAL_MASK 0xFF +#define LCC_MI2S_MD_NOT_2D_VAL_SHIFT 0 + +#define LCC_MI2S_STAT_OSR_CLK_MASK 0x2 +#define LCC_MI2S_STAT_OSR_CLK_SHIFT 1 +#define LCC_MI2S_STAT_OSR_CLK_ON (1 << LCC_MI2S_STAT_OSR_CLK_SHIFT) + +#define LCC_MI2S_STAT_BIT_CLK_MASK 0x1 +#define LCC_MI2S_STAT_BIT_CLK_SHIFT 0 +#define LCC_MI2S_STAT_BIT_CLK_ON (1 << LCC_MI2S_STAT_BIT_CLK_SHIFT) + +/* LCC PLL Configuration/Control */ + +#define LCC_PLL_PCLK_REG 0xC4 +#define LCC_PLL_SCLK_REG 0xC8 + +#define LCC_PLL_PCLK_RESET_MASK 0x2 +#define LCC_PLL_PCLK_RESET_SHIFT 1 +#define LCC_PLL_PCLK_RESET_ASSERT (1 << LCC_PLL_PCLK_RESET_SHIFT) + +#define LCC_PLL_PCLK_SRC_MASK 0x1 +#define LCC_PLL_PCLK_SRC_SHIFT 0 +#define LCC_PLL_PCLK_SRC_PXO (0 << LCC_PLL_PCLK_SRC_SHIFT) +#define LCC_PLL_PCLK_SRC_PRI (1 << LCC_PLL_PCLK_SRC_SHIFT) + +#define LCC_PLL_SCLK_RESET_MASK 0x10 +#define LCC_PLL_SCLK_RESET_SHIFT 4 +#define LCC_PLL_SCLK_RESET_ASSERT (1 << LCC_PLL_SCLK_RESET_SHIFT) + +#define LCC_PLL_SCLK_DIV_MASK 0xC +#define LCC_PLL_SCLK_DIV_SHIFT 2 +#define LCC_PLL_SCLK_DIV_BYPASS (0 << LCC_PLL_SCLK_DIV_SHIFT) +#define LCC_PLL_SCLK_DIV_DIV2 (1 << LCC_PLL_SCLK_DIV_SHIFT) +#define LCC_PLL_SCLK_DIV_DIV3 (2 << LCC_PLL_SCLK_DIV_SHIFT) +#define LCC_PLL_SCLK_DIV_DIV4 (3 << LCC_PLL_SCLK_DIV_SHIFT) + +#define LCC_PLL_SCLK_XO_MASK 0x2 +#define LCC_PLL_SCLK_XO_SHIFT 1 +#define LCC_PLL_SCLK_XO_PXO (0 << LCC_PLL_SCLK_XO_SHIFT) +#define LCC_PLL_SCLK_XO_SEC (1 << LCC_PLL_SCLK_XO_SHIFT) + +#define LCC_PLL_SCLK_MUX_MASK 0x1 +#define LCC_PLL_SCLK_MUX_SHIFT 0 +#define LCC_PLL_SCLK_MUX_PLL1 (0 << LCC_PLL_SCLK_MUX_SHIFT) +#define LCC_PLL_SCLK_MUX_PLL0 (1 << LCC_PLL_SCLK_MUX_SHIFT) + +#endif /* __DRIVERS_CLOCK_IPQ40XX_LCC_REG_H__ */ diff --git a/src/soc/qualcomm/ipq40xx/include/soc/memlayout.ld b/src/soc/qualcomm/ipq40xx/include/soc/memlayout.ld new file mode 100644 index 0000000000..6ff2b77608 --- /dev/null +++ b/src/soc/qualcomm/ipq40xx/include/soc/memlayout.ld @@ -0,0 +1,51 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * Copyright 2014 Google Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * 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 <memlayout.h> + +#include <arch/header.ld> + +SECTIONS +{ + REGION(rpm, 0x00020000, 160K, 8K) + SRAM_START(0x2A000000) + /* This includes bootblock image, can be reused after bootblock starts */ +/* UBER_SBL(0x2A000000, 48K) */ +/* DDR(0x2A000000, 48K) */ + BOOTBLOCK(0x2A00C000, 24K) + OVERLAP_VERSTAGE_ROMSTAGE(0x2A012000, 64K) + VBOOT2_WORK(0x2A022000, 16K) + PRERAM_CBMEM_CONSOLE(0x2A026000, 32K) + TIMESTAMP(0x2A02E000, 1K) + +/* 0x2e400..0x3F000 67 KB free */ + +/* Keep the below area reserved at all times, it is used by various QCA + components as shared data + QCA_SHARED_RAM(2A03F000, 4K) +*/ + STACK(0x2A040000, 16K) + PRERAM_CBFS_CACHE(0x2A044000, 93K) + TTB_SUBTABLES(0x2A05B800, 2K) + TTB(0x2A05C000, 16K) + SRAM_END(0x2A060000) + + DRAM_START(0x40000000) + RAMSTAGE(0x40640000, 128K) + SYMBOL(memlayout_cbmem_top, 0x59F80000) + POSTRAM_CBFS_CACHE(0x59F80000, 384K) + DMA_COHERENT(0x5A000000, 2M) +} diff --git a/src/soc/qualcomm/ipq40xx/include/soc/qup.h b/src/soc/qualcomm/ipq40xx/include/soc/qup.h new file mode 100644 index 0000000000..d0186f59b0 --- /dev/null +++ b/src/soc/qualcomm/ipq40xx/include/soc/qup.h @@ -0,0 +1,219 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2014 - 2015 The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __QUP_H__ +#define __QUP_H__ + +#include <soc/gsbi.h> + +/* QUP block registers */ +#define QUP_CONFIG 0x0 +#define QUP_STATE 0x4 +#define QUP_IO_MODES 0x8 +#define QUP_SW_RESET 0xc +#define QUP_TIME_OUT 0x10 +#define QUP_TIME_OUT_CURRENT 0x14 +#define QUP_OPERATIONAL 0x18 +#define QUP_ERROR_FLAGS 0x1c +#define QUP_ERROR_FLAGS_EN 0x20 +#define QUP_TEST_CTRL 0x24 +#define QUP_MX_OUTPUT_COUNT 0x100 +#define QUP_MX_OUTPUT_CNT_CURRENT 0x104 +#define QUP_OUTPUT_DEBUG 0x108 +#define QUP_OUTPUT_FIFO_WORD_CNT 0x10c +#define QUP_OUTPUT_FIFO 0x110 +#define QUP_MX_WRITE_COUNT 0x150 +#define QUP_WRITE_CNT_CURRENT 0x154 +#define QUP_MX_INPUT_COUNT 0x200 +#define QUP_READ_COUNT 0x208 +#define QUP_MX_READ_CNT_CURRENT 0x20c +#define QUP_INPUT_DEBUG 0x210 +#define QUP_INPUT_FIFO_WORD_CNT 0x214 +#define QUP_INPUT_FIFO 0x218 +#define QUP_I2C_MASTER_CLK_CTL 0x400 +#define QUP_I2C_MASTER_STATUS 0x404 + +#define OUTPUT_FIFO_FULL (1<<6) +#define INPUT_FIFO_NOT_EMPTY (1<<5) +#define OUTPUT_FIFO_NOT_EMPTY (1<<4) +#define INPUT_SERVICE_FLAG (1<<9) +#define OUTPUT_SERVICE_FLAG (1<<8) +#define QUP_OUTPUT_BIT_SHIFT_EN (1<<16) + +#define QUP_MODE_MASK (0x03) +#define QUP_OUTPUT_MODE_SHFT (10) +#define QUP_INPUT_MODE_SHFT (12) + +#define QUP_FS_DIVIDER_MASK (0xFF) + +#define QUP_MINI_CORE_PROTO_SHFT (8) +#define QUP_MINI_CORE_PROTO_MASK (0x0F) + +/* Mini-core states */ +#define QUP_STATE_RESET 0x0 +#define QUP_STATE_RUN 0x1 +#define QUP_STATE_PAUSE 0x3 +#define QUP_STATE_VALID (1<<2) +#define QUP_STATE_MASK 0x3 +#define QUP_STATE_VALID_MASK (1<<2) + +/* Tags for output FIFO */ +#define QUP_I2C_1CLK_NOOP_SEQ 0x1 /*MSB 8-bit NOP, LSB 8-bits 1 clk.*/ +#define QUP_I2C_START_SEQ (0x1 << 8) +#define QUP_I2C_DATA_SEQ (0x2 << 8) +#define QUP_I2C_STOP_SEQ (0x3 << 8) +#define QUP_I2C_RECV_SEQ (0x4 << 8) + +/* Tags for input FIFO */ +#define QUP_I2C_MIDATA_SEQ (0x5 << 8) +#define QUP_I2C_MISTOP_SEQ (0x6 << 8) +#define QUP_I2C_MINACK_SEQ (0x7 << 8) + +#define QUP_I2C_ADDR(x) ((x & 0xFF) << 1) +#define QUP_I2C_DATA(x) (x & 0xFF) +#define QUP_I2C_MI_TAG(x) (x & 0xFF00) +#define QUP_I2C_SLAVE_READ (0x1) + +/*Bit vals for I2C_MASTER_CLK_CTL register */ +#define QUP_HS_DIVIDER_SHFT (8) +#define QUP_DIVIDER_MIN_VAL (0x3) + +/* Bit masks for I2C_MASTER_STATUS register */ +#define QUP_I2C_INVALID_READ_SEQ (1 << 25) +#define QUP_I2C_INVALID_READ_ADDR (1 << 24) +#define QUP_I2C_INVALID_TAG (1 << 23) +#define QUP_I2C_FAILED_MASK (0x3 << 6) +#define QUP_I2C_INVALID_WRITE (1 << 5) +#define QUP_I2C_ARB_LOST (1 << 4) +#define QUP_I2C_PACKET_NACK (1 << 3) +#define QUP_I2C_BUS_ERROR (1 << 2) + +typedef enum { + QUP_SUCCESS = 0, + QUP_ERR_BAD_PARAM, + QUP_ERR_STATE_SET, + QUP_ERR_TIMEOUT, + QUP_ERR_UNSUPPORTED, + QUP_ERR_I2C_FAILED, + QUP_ERR_I2C_ARB_LOST, + QUP_ERR_I2C_BUS_ERROR, + QUP_ERR_I2C_INVALID_SLAVE_ADDR, + QUP_ERR_XFER_FAIL, + QUP_ERR_I2C_NACK, + QUP_ERR_I2C_INVALID_WRITE, + QUP_ERR_I2C_INVALID_TAG, + QUP_ERR_UNDEFINED, +} qup_return_t; + +typedef enum { + QUP_MINICORE_SPI = 1, + QUP_MINICORE_I2C_MASTER, + QUP_MINICORE_I2C_SLAVE +} qup_protocol_t; + +typedef enum { + QUP_MODE_FIFO = 0, + QUP_MODE_BLOCK, + QUP_MODE_DATAMOVER, +} qup_mode_t; + +typedef struct { + qup_protocol_t protocol; + unsigned clk_frequency; + unsigned src_frequency; + qup_mode_t mode; + unsigned initialized; +} qup_config_t; + +typedef struct { + qup_protocol_t protocol; + union { + struct { + uint8_t addr; + uint8_t *data; + unsigned data_len; + } iic; + struct { + void *in; + void *out; + unsigned size; + } spi; + } p; +} qup_data_t; + +/* + * Initialize GSBI QUP block for FIFO I2C transfers. + * gsbi_id[IN]: GSBI for which QUP is to be initialized. + * config_ptr[IN]: configurations parameters for the QUP. + * + * return: QUP_SUCCESS, if initialization succeeds. + */ +qup_return_t qup_init(gsbi_id_t gsbi_id, const qup_config_t *config_ptr); + +/* + * Set QUP state to run, pause, reset. + * gsbi_id[IN]: GSBI block for which QUP state is to be set. + * state[IN]: New state to transition to. + * + * return: QUP_SUCCESS, if state transition succeeds. + */ +qup_return_t qup_set_state(gsbi_id_t gsbi_id, uint32_t state); + +/* + * Reset the status bits set during an i2c transfer. + * gsbi_id[IN]: GSBI block for which i2c status bits are to be cleared. + * + * return: QUP_SUCCESS, if status bits are cleared successfully. + */ +qup_return_t qup_reset_i2c_master_status(gsbi_id_t gsbi_id); + +/* + * Send data to the peripheral on the bus. + * gsbi_id[IN]: GSBI block for which data is to be sent. + * p_tx_obj[IN]: Data to be sent to the slave on the bus. + * stop_seq[IN]: When set to non-zero QUP engine sends i2c stop sequnce. + * + * return: QUP_SUCCESS, when data is sent successfully to the peripheral. + */ +qup_return_t qup_send_data(gsbi_id_t gsbi_id, qup_data_t *p_tx_obj, + uint8_t stop_seq); + +/* + * Receive data from peripheral on the bus. + * gsbi_id[IN]: GSBI block from which data is to be received. + * p_tx_obj[IN]: length of data to be received, slave address. + * [OUT]: buffer filled with data from slave. + * + * return: QUP_SUCCESS, when data is received successfully. + */ +qup_return_t qup_recv_data(gsbi_id_t gsbi_id, qup_data_t *p_tx_obj); + +#endif //__QUP_H__ diff --git a/src/soc/qualcomm/ipq40xx/include/soc/soc_services.h b/src/soc/qualcomm/ipq40xx/include/soc/soc_services.h new file mode 100644 index 0000000000..5ad11f1a10 --- /dev/null +++ b/src/soc/qualcomm/ipq40xx/include/soc/soc_services.h @@ -0,0 +1,35 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2014 Google Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * 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. + */ + +#ifndef __SOC_QUALCOMM_IPQ40XX_INCLUDE_SOC_SOC_SERVICES_H__ +#define __SOC_QUALCOMM_IPQ40XX_INCLUDE_SOC_SOC_SERVICES_H__ + +#include <types.h> + +extern u8 _memlayout_cbmem_top[]; + +/* Returns zero on success, nonzero on failure. */ +int initialize_dram(void); + +/* Loads and runs TZBSP, switches into user mode. */ +void start_tzbsp(void); + +/* A helper function needed to start TZBSP properly. */ +int tz_init_wrapper(int, int, void *); + +/* Load RPM code into memory and trigger its execution. */ +void start_rpm(void); + +#endif diff --git a/src/soc/qualcomm/ipq40xx/include/soc/spi.h b/src/soc/qualcomm/ipq40xx/include/soc/spi.h new file mode 100644 index 0000000000..8e52d62a01 --- /dev/null +++ b/src/soc/qualcomm/ipq40xx/include/soc/spi.h @@ -0,0 +1,305 @@ +/* + * Register definitions for the IPQ GSBI Controller + * + * Copyright (c) 2012 The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _IPQ40XX_SPI_H_ +#define _IPQ40XX_SPI_H_ + +#include <spi_flash.h> +#include <soc/iomap.h> + +#define QUP5_BASE ((uint32_t)GSBI_QUP5_BASE) +#define QUP6_BASE ((uint32_t)GSBI_QUP6_BASE) +#define QUP7_BASE ((uint32_t)GSBI_QUP7_BASE) + +#define GSBI5_QUP5_REG_BASE (QUP5_BASE + 0x00000000) +#define GSBI6_QUP6_REG_BASE (QUP6_BASE + 0x00000000) +#define GSBI7_QUP7_REG_BASE (QUP7_BASE + 0x00000000) + +#define GSBI5_REG_BASE ((uint32_t)(GSBI5_BASE + 0x00000000)) +#define GSBI6_REG_BASE ((uint32_t)(GSBI6_BASE + 0x00000000)) +#define GSBI7_REG_BASE ((uint32_t)(GSBI7_BASE + 0x00000000)) + +#define BOOT_SPI_PORT5_BASE QUP5_BASE +#define BOOT_SPI_PORT6_BASE QUP6_BASE +#define BOOT_SPI_PORT7_BASE QUP7_BASE + +#define GSBI5_SPI_CONFIG_REG (GSBI5_QUP5_REG_BASE + 0x00000300) +#define GSBI6_SPI_CONFIG_REG (GSBI6_QUP6_REG_BASE + 0x00000300) +#define GSBI7_SPI_CONFIG_REG (GSBI7_QUP7_REG_BASE + 0x00000300) + +#define GSBI5_SPI_IO_CONTROL_REG (GSBI5_QUP5_REG_BASE + 0x00000304) +#define GSBI6_SPI_IO_CONTROL_REG (GSBI6_QUP6_REG_BASE + 0x00000304) +#define GSBI7_SPI_IO_CONTROL_REG (GSBI7_QUP7_REG_BASE + 0x00000304) + +#define GSBI5_SPI_ERROR_FLAGS_REG (GSBI5_QUP5_REG_BASE + 0x00000308) +#define GSBI6_SPI_ERROR_FLAGS_REG (GSBI6_QUP6_REG_BASE + 0x00000308) +#define GSBI7_SPI_ERROR_FLAGS_REG (GSBI7_QUP7_REG_BASE + 0x00000308) + +#define GSBI5_SPI_ERROR_FLAGS_EN_REG (GSBI5_QUP5_REG_BASE + 0x0000030c) +#define GSBI6_SPI_ERROR_FLAGS_EN_REG (GSBI6_QUP6_REG_BASE + 0x0000030c) +#define GSBI7_SPI_ERROR_FLAGS_EN_REG (GSBI7_QUP7_REG_BASE + 0x0000030c) + +#define GSBI5_GSBI_CTRL_REG_REG (GSBI5_REG_BASE + 0x00000000) +#define GSBI6_GSBI_CTRL_REG_REG (GSBI6_REG_BASE + 0x00000000) +#define GSBI7_GSBI_CTRL_REG_REG (GSBI7_REG_BASE + 0x00000000) + +#define GSBI5_QUP_CONFIG_REG (GSBI5_QUP5_REG_BASE + 0x00000000) +#define GSBI6_QUP_CONFIG_REG (GSBI6_QUP6_REG_BASE + 0x00000000) +#define GSBI7_QUP_CONFIG_REG (GSBI7_QUP7_REG_BASE + 0x00000000) + +#define GSBI5_QUP_ERROR_FLAGS_REG (GSBI5_QUP5_REG_BASE + 0x0000001c) +#define GSBI6_QUP_ERROR_FLAGS_REG (GSBI6_QUP6_REG_BASE + 0x0000001c) +#define GSBI7_QUP_ERROR_FLAGS_REG (GSBI7_QUP7_REG_BASE + 0x0000001c) + +#define GSBI5_QUP_ERROR_FLAGS_EN_REG (GSBI5_QUP5_REG_BASE + 0x00000020) +#define GSBI6_QUP_ERROR_FLAGS_EN_REG (GSBI6_QUP6_REG_BASE + 0x00000020) +#define GSBI7_QUP_ERROR_FLAGS_EN_REG (GSBI7_QUP7_REG_BASE + 0x00000020) + +#define GSBI5_QUP_OPERATIONAL_REG (GSBI5_QUP5_REG_BASE + 0x00000018) +#define GSBI6_QUP_OPERATIONAL_REG (GSBI6_QUP6_REG_BASE + 0x00000018) +#define GSBI7_QUP_OPERATIONAL_REG (GSBI7_QUP7_REG_BASE + 0x00000018) + +#define GSBI5_QUP_IO_MODES_REG (GSBI5_QUP5_REG_BASE + 0x00000008) +#define GSBI6_QUP_IO_MODES_REG (GSBI6_QUP6_REG_BASE + 0x00000008) +#define GSBI7_QUP_IO_MODES_REG (GSBI7_QUP7_REG_BASE + 0x00000008) + +#define GSBI5_QUP_STATE_REG (GSBI5_QUP5_REG_BASE + 0x00000004) +#define GSBI6_QUP_STATE_REG (GSBI6_QUP6_REG_BASE + 0x00000004) +#define GSBI7_QUP_STATE_REG (GSBI7_QUP7_REG_BASE + 0x00000004) + +#define GSBI5_QUP_OUT_FIFO_WORD_CNT_REG (GSBI5_QUP5_REG_BASE + 0x0000010c) +#define GSBI6_QUP_OUT_FIFO_WORD_CNT_REG (GSBI6_QUP6_REG_BASE + 0x0000010c) +#define GSBI7_QUP_OUT_FIFO_WORD_CNT_REG (GSBI7_QUP7_REG_BASE + 0x0000010c) + +#define GSBI5_QUP_IN_FIFO_WORD_CNT_REG (GSBI5_QUP5_REG_BASE + 0x00000214) +#define GSBI6_QUP_IN_FIFO_WORD_CNT_REG (GSBI6_QUP6_REG_BASE + 0x00000214) +#define GSBI7_QUP_IN_FIFO_WORD_CNT_REG (GSBI7_QUP7_REG_BASE + 0x00000214) + +#define GSBI5_QUP_INPUT_FIFOc_REG(c) \ + (GSBI5_QUP5_REG_BASE + 0x00000218 + 4 * (c)) +#define GSBI6_QUP_INPUT_FIFOc_REG(c) \ + (GSBI6_QUP6_REG_BASE + 0x00000218 + 4 * (c)) +#define GSBI7_QUP_INPUT_FIFOc_REG(c) \ + (GSBI7_QUP7_REG_BASE + 0x00000218 + 4 * (c)) + +#define GSBI5_QUP_OUTPUT_FIFOc_REG(c) \ + (GSBI5_QUP5_REG_BASE + 0x00000110 + 4 * (c)) +#define GSBI6_QUP_OUTPUT_FIFOc_REG(c) \ + (GSBI6_QUP6_REG_BASE + 0x00000110 + 4 * (c)) +#define GSBI7_QUP_OUTPUT_FIFOc_REG(c) \ + (GSBI7_QUP7_REG_BASE + 0x00000110 + 4 * (c)) + +#define GSBI5_QUP_MX_INPUT_COUNT_REG (GSBI5_QUP5_REG_BASE + 0x00000200) +#define GSBI6_QUP_MX_INPUT_COUNT_REG (GSBI6_QUP6_REG_BASE + 0x00000200) +#define GSBI7_QUP_MX_INPUT_COUNT_REG (GSBI7_QUP7_REG_BASE + 0x00000200) + +#define GSBI5_QUP_MX_OUTPUT_COUNT_REG (GSBI5_QUP5_REG_BASE + 0x00000100) +#define GSBI6_QUP_MX_OUTPUT_COUNT_REG (GSBI6_QUP6_REG_BASE + 0x00000100) +#define GSBI7_QUP_MX_OUTPUT_COUNT_REG (GSBI7_QUP7_REG_BASE + 0x00000100) + +#define GSBI5_QUP_SW_RESET_REG (GSBI5_QUP5_REG_BASE + 0x0000000c) +#define GSBI6_QUP_SW_RESET_REG (GSBI6_QUP6_REG_BASE + 0x0000000c) +#define GSBI7_QUP_SW_RESET_REG (GSBI7_QUP7_REG_BASE + 0x0000000c) + +#define CLK_CTL_REG_BASE 0x00900000 +#define GSBIn_RESET_REG(n) \ + (CLK_CTL_REG_BASE + 0x000029dc + 32 * ((n)-1)) + +#define SFAB_AHB_S3_FCLK_CTL_REG \ + (CLK_CTL_REG_BASE + 0x0000216c) +#define CFPB_CLK_NS_REG \ + (CLK_CTL_REG_BASE + 0x0000264c) +#define SFAB_CFPB_S_HCLK_CTL_REG \ + (CLK_CTL_REG_BASE + 0x000026c0) +#define CFPB_SPLITTER_HCLK_CTL_REG \ + (CLK_CTL_REG_BASE + 0x000026e0) +#define CFPB0_HCLK_CTL_REG \ + (CLK_CTL_REG_BASE + 0x00002650) +#define CFPB2_HCLK_CTL_REG \ + (CLK_CTL_REG_BASE + 0x00002658) +#define GSBIn_HCLK_CTL_REG(n) \ + (CLK_CTL_REG_BASE + 0x000029c0 + 32 * ((n)-1)) +#define GSBIn_QUP_APPS_NS_REG(n) \ + (CLK_CTL_REG_BASE + 0x000029cc + 32 * ((n)-1)) +#define GSBIn_QUP_APPS_MD_REG(n) \ + (CLK_CTL_REG_BASE + 0x000029c8 + 32 * ((n)-1)) +#define CLK_HALT_CFPB_STATEB_REG \ + (CLK_CTL_REG_BASE + 0x00002fd0) + +#define GSBI5_HCLK 23 +#define GSBI6_HCLK 19 +#define GSBI7_HCLK 15 +#define GSBI5_QUP_APPS_CLK 20 +#define GSBI6_QUP_APPS_CLK 16 +#define GSBI7_QUP_APPS_CLK 12 +#define GSBI_CLK_BRANCH_ENA_MSK (1 << 4) +#define GSBI_CLK_BRANCH_ENA (1 << 4) +#define GSBI_CLK_BRANCH_DIS (0 << 4) +#define QUP_CLK_BRANCH_ENA_MSK (1 << 9) +#define QUP_CLK_BRANCH_ENA (1 << 9) +#define QUP_CLK_BRANCH_DIS (0 << 9) +#define CLK_ROOT_ENA_MSK (1 << 11) +#define CLK_ROOT_ENA (1 << 11) +#define CLK_ROOT_DIS (0 << 11) + +#define QUP_STATE_VALID_BIT 2 +#define QUP_STATE_VALID 1 +#define QUP_STATE_MASK 0x3 +#define QUP_CONFIG_MINI_CORE_MSK (0x0F << 8) +#define QUP_CONFIG_MINI_CORE_SPI (1 << 8) +#define SPI_QUP_CONF_INPUT_MSK (1 << 7) +#define SPI_QUP_CONF_INPUT_ENA (0 << 7) +#define SPI_QUP_CONF_NO_INPUT (1 << 7) +#define SPI_QUP_CONF_OUTPUT_MSK (1 << 6) +#define SPI_QUP_CONF_OUTPUT_ENA (0 << 6) +#define SPI_QUP_CONF_NO_OUTPUT (1 << 6) +#define SPI_QUP_CONF_OUTPUT_ENA (0 << 6) +#define QUP_STATE_RESET_STATE 0x0 +#define QUP_STATE_RUN_STATE 0x1 +#define QUP_STATE_PAUSE_STATE 0x3 +#define SPI_BIT_WORD_MSK 0x1F +#define SPI_8_BIT_WORD 0x07 +#define PROTOCOL_CODE_MSK (0x07 << 4) +#define PROTOCOL_CODE_SPI (0x03 << 4) +#define LOOP_BACK_MSK (1 << 8) +#define NO_LOOP_BACK (0 << 8) +#define SLAVE_OPERATION_MSK (1 << 5) +#define SLAVE_OPERATION (0 << 5) +#define CLK_ALWAYS_ON (0 << 9) +#define MX_CS_MODE (0 << 8) +#define NO_TRI_STATE (1 << 0) +#define OUTPUT_BIT_SHIFT_MSK (1 << 16) +#define OUTPUT_BIT_SHIFT_EN (1 << 16) +#define INPUT_BLOCK_MODE_MSK (0x03 << 12) +#define INPUT_BLOCK_MODE (0x01 << 12) +#define OUTPUT_BLOCK_MODE_MSK (0x03 << 10) +#define OUTPUT_BLOCK_MODE (0x01 << 10) +#define GSBI1_RESET (1 << 0) +#define GSBI1_RESET_MSK 0x1 + +#define GSBI_M_VAL_SHFT 16 +#define GSBIn_M_VAL_MSK (0xFF << GSBI_M_VAL_SHFT) +#define GSBI_N_VAL_SHFT 16 +#define GSBIn_N_VAL_MSK (0xFF << GSBI_N_VAL_SHFT) +#define GSBI_D_VAL_SHFT 0 +#define GSBIn_D_VAL_MSK (0xFF << GSBI_D_VAL_SHFT) +#define MNCNTR_RST_MSK (1 << 7) +#define MNCNTR_RST_ENA (1 << 7) +#define MNCNTR_RST_DIS (0 << 7) +#define MNCNTR_MSK (1 << 8) +#define MNCNTR_EN (1 << 8) +#define MNCNTR_DIS (0 << 8) +#define MNCNTR_MODE_MSK (0x3 << 5) +#define MNCNTR_MODE_BYPASS (0 << 5) +#define MNCNTR_MODE_DUAL_EDGE (0x2 << 5) +#define GSBI_PRE_DIV_SEL_SHFT 3 +#define GSBIn_PRE_DIV_SEL_MSK (0x3 << GSBI_PRE_DIV_SEL_SHFT) +#define GSBIn_PLL_SRC_MSK (0x03 << 0) +#define GSBIn_PLL_SRC_PXO (0 << 0) +#define GSBIn_PLL_SRC_PLL8 (0x3 << 0) + +#define SPI_INPUT_FIRST_MODE (1 << 9) +#define SPI_IO_CONTROL_CLOCK_IDLE_HIGH (1 << 10) +#define QUP_DATA_AVAILABLE_FOR_READ (1 << 5) +#define QUP_OUTPUT_FIFO_NOT_EMPTY (1 << 4) +#define OUTPUT_SERVICE_FLAG (1 << 8) +#define INPUT_SERVICE_FLAG (1 << 9) +#define QUP_OUTPUT_FIFO_FULL (1 << 6) +#define QUP_INPUT_FIFO_NOT_EMPTY (1 << 5) +#define SPI_INPUT_BLOCK_SIZE 4 +#define SPI_OUTPUT_BLOCK_SIZE 4 +#define GSBI5_SPI_CLK 21 +#define GSBI5_SPI_MISO 19 +#define GSBI5_SPI_MOSI 18 +#define GSBI5_SPI_CS_0 20 +#define GSBI5_SPI_CS_1 61 +#define GSBI5_SPI_CS_2 62 +#define GSBI5_SPI_CS_3 2 +#define GSBI6_SPI_CLK 30 +#define GSBI6_SPI_CS_0 29 +#define GSBI6_SPI_MISO 28 +#define GSBI6_SPI_MOSI 27 +#define GSBI7_SPI_CLK 9 +#define GSBI7_SPI_CS_0 8 +#define GSBI7_SPI_MISO 7 +#define GSBI7_SPI_MOSI 6 + +#define MSM_GSBI_MAX_FREQ 51200000 + +#define SPI_RESET_STATE 0 +#define SPI_RUN_STATE 1 +#define SPI_PAUSE_STATE 3 +#define SPI_CORE_RESET 0 +#define SPI_CORE_RUNNING 1 +#define GSBI_SPI_MODE_0 0 +#define GSBI_SPI_MODE_1 1 +#define GSBI_SPI_MODE_2 2 +#define GSBI_SPI_MODE_3 3 +#define GSBI5_SPI 0 +#define GSBI6_SPI 1 +#define GSBI7_SPI 2 + +struct gsbi_spi { + unsigned int spi_config; + unsigned int io_control; + unsigned int error_flags; + unsigned int error_flags_en; + unsigned int gsbi_ctrl; + unsigned int qup_config; + unsigned int qup_error_flags; + unsigned int qup_error_flags_en; + unsigned int qup_operational; + unsigned int qup_io_modes; + unsigned int qup_state; + unsigned int qup_input_fifo; + unsigned int qup_output_fifo; + unsigned int qup_mx_input_count; + unsigned int qup_mx_output_count; + unsigned int qup_sw_reset; + unsigned int qup_ns_reg; + unsigned int qup_md_reg; +}; + +struct ipq_spi_slave { + struct spi_slave slave; + const struct gsbi_spi *regs; + unsigned int mode; + unsigned int initialized; + unsigned long freq; + int allocated; +}; + +static inline struct ipq_spi_slave *to_ipq_spi(struct spi_slave *slave) +{ + return container_of(slave, struct ipq_spi_slave, slave); +} + +#endif /* _IPQ40XX_SPI_H_ */ diff --git a/src/soc/qualcomm/ipq40xx/include/soc/usb.h b/src/soc/qualcomm/ipq40xx/include/soc/usb.h new file mode 100644 index 0000000000..457ead7ec1 --- /dev/null +++ b/src/soc/qualcomm/ipq40xx/include/soc/usb.h @@ -0,0 +1,22 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2014 Google Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * 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. + */ + +#ifndef _IPQ40XX_USB_H_ +#define _IPQ40XX_USB_H_ + +void setup_usb_host1(void); +void setup_usb_host2(void); + +#endif /* _IPQ40XX_USB_H_ */ diff --git a/src/soc/qualcomm/ipq40xx/include/soc/usbl_if.h b/src/soc/qualcomm/ipq40xx/include/soc/usbl_if.h new file mode 100644 index 0000000000..134b63f19c --- /dev/null +++ b/src/soc/qualcomm/ipq40xx/include/soc/usbl_if.h @@ -0,0 +1,70 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2015 The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __SOC_QUALCOMM_IPQ40XX_INCLUDE_SOC_USBL_IF_H__ +#define __SOC_QUALCOMM_IPQ40XX_INCLUDE_SOC_USBL_IF_H__ + +#include <types.h> + +typedef struct { + u32 time_stamp; + char msg[27]; + u8 type; + +} boot_log_entry; + +typedef struct { + u32 num_log_entries; + boot_log_entry *log; +} sbl_ro_info; + +typedef struct { + u32 start_magic; + u32 num; + char *version; + sbl_ro_info info[2]; + /* + * The two addresses below can be used for communicating with the RPM + * (passing it the starting address of the program to execute and + * triggering the jump to the program). Presently these addresses are + * hardcodeded in firmware source code. + */ + u32 *rpm_jump_trigger; + u32 *rpm_entry_addr_ptr; + u32 end_magic; +} uber_sbl_shared_info; + +#define UBER_SBL_SHARED_INFO_START_MAGIC 0x5552504d // URPM +#define UBER_SBL_SHARED_INFO_END_MAGIC 0x554b5254 // UKRT + +extern uber_sbl_shared_info *maskrom_param; + +#endif diff --git a/src/soc/qualcomm/ipq40xx/lcc.c b/src/soc/qualcomm/ipq40xx/lcc.c new file mode 100644 index 0000000000..d577487618 --- /dev/null +++ b/src/soc/qualcomm/ipq40xx/lcc.c @@ -0,0 +1,316 @@ +/* + * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdlib.h> +#include <stdint.h> +#include <delay.h> +#include <console/console.h> +#include <soc/clock.h> +#include <soc/lcc-reg.h> +#include <arch/io.h> + +typedef struct { + void *gcc_apcs_regs; + void *lcc_pll0_regs; + void *lcc_ahbix_regs; + void *lcc_mi2s_regs; + void *lcc_pll_regs; +} Ipq806xLccClocks; + +typedef struct __attribute__((packed)) { + uint32_t apcs; +} Ipq806xLccGccRegs; + +typedef struct __attribute__((packed)) { + uint32_t mode; + uint32_t l_val; + uint32_t m_val; + uint32_t n_val; + uint32_t UNUSED; + uint32_t config; + uint32_t status; +} Ipq806xLccPll0Regs; + +typedef struct __attribute__((packed)) { + uint32_t ns; + uint32_t md; + uint32_t UNUSED; + uint32_t status; +} Ipq806xLccAhbixRegs; + +typedef struct __attribute__((packed)) { + uint32_t ns; + uint32_t md; + uint32_t status; +} Ipq806xLccMi2sRegs; + +typedef struct __attribute__((packed)) { + uint32_t pri; + uint32_t sec; +} Ipq806xLccPllRegs; + +struct lcc_freq_tbl { + unsigned freq; + unsigned pd; + unsigned m; + unsigned n; + unsigned d; +}; + +static const struct lcc_freq_tbl lcc_mi2s_freq_tbl[] = { + { 1024000, 4, 1, 96, 8 }, + { 1411200, 4, 2, 139, 8 }, + { 1536000, 4, 1, 64, 8 }, + { 2048000, 4, 1, 48, 8 }, + { 2116800, 4, 2, 93, 8 }, + { 2304000, 4, 2, 85, 8 }, + { 2822400, 4, 6, 209, 8 }, + { 3072000, 4, 1, 32, 8 }, + { 3175200, 4, 1, 31, 8 }, + { 4096000, 4, 1, 24, 8 }, + { 4233600, 4, 9, 209, 8 }, + { 4608000, 4, 3, 64, 8 }, + { 5644800, 4, 12, 209, 8 }, + { 6144000, 4, 1, 16, 8 }, + { 6350400, 4, 2, 31, 8 }, + { 8192000, 4, 1, 12, 8 }, + { 8467200, 4, 18, 209, 8 }, + { 9216000, 4, 3, 32, 8 }, + { 11289600, 4, 24, 209, 8 }, + { 12288000, 4, 1, 8, 8 }, + { 12700800, 4, 27, 209, 8 }, + { 13824000, 4, 9, 64, 8 }, + { 16384000, 4, 1, 6, 8 }, + { 16934400, 4, 41, 238, 8 }, + { 18432000, 4, 3, 16, 8 }, + { 22579200, 2, 24, 209, 8 }, + { 24576000, 4, 1, 4, 8 }, + { 27648000, 4, 9, 32, 8 }, + { 33868800, 4, 41, 119, 8 }, + { 36864000, 4, 3, 8, 8 }, + { 45158400, 1, 24, 209, 8 }, + { 49152000, 4, 1, 2, 8 }, + { 50803200, 1, 27, 209, 8 }, + { } +}; + +static int lcc_init_enable_pll0(Ipq806xLccClocks *bus) +{ + Ipq806xLccGccRegs *gcc_regs = bus->gcc_apcs_regs; + Ipq806xLccPll0Regs *pll0_regs = bus->lcc_pll0_regs; + Ipq806xLccPllRegs *pll_regs = bus->lcc_pll_regs; + uint32_t regval; + + regval = 0; + regval = 15 << LCC_PLL0_L_SHIFT & LCC_PLL0_L_MASK; + write32(&pll0_regs->l_val, regval); + + regval = 0; + regval = 145 << LCC_PLL0_M_SHIFT & LCC_PLL0_M_MASK; + write32(&pll0_regs->m_val, regval); + + regval = 0; + regval = 199 << LCC_PLL0_N_SHIFT & LCC_PLL0_N_MASK; + write32(&pll0_regs->n_val, regval); + + regval = 0; + regval |= LCC_PLL0_CFG_LV_MAIN_ENABLE; + regval |= LCC_PLL0_CFG_FRAC_ENABLE; + write32(&pll0_regs->config, regval); + + regval = 0; + regval |= LCC_PLL_PCLK_SRC_PRI; + write32(&pll_regs->pri, regval); + + regval = 0; + regval |= 1 << LCC_PLL0_MODE_BIAS_CNT_SHIFT & + LCC_PLL0_MODE_BIAS_CNT_MASK; + regval |= 8 << LCC_PLL0_MODE_LOCK_CNT_SHIFT & + LCC_PLL0_MODE_LOCK_CNT_MASK; + write32(&pll0_regs->mode, regval); + + regval = read32(&gcc_regs->apcs); + regval |= GCC_PLL_APCS_PLL4_ENABLE; + write32(&gcc_regs->apcs, regval); + + regval = read32(&pll0_regs->mode); + regval |= LCC_PLL0_MODE_FSM_VOTE_ENABLE; + write32(&pll0_regs->mode, regval); + + mdelay(1); + + regval = read32(&pll0_regs->status); + if (regval & LCC_PLL0_STAT_ACTIVE_MASK) + return 0; + + printk(BIOS_ERR, "%s: error enabling PLL4 clock\n", __func__); + return 1; +} + +static int lcc_init_enable_ahbix(Ipq806xLccClocks *bus) +{ + Ipq806xLccAhbixRegs *ahbix_regs = bus->lcc_ahbix_regs; + uint32_t regval; + + regval = 0; + regval |= 1 << LCC_AHBIX_MD_M_VAL_SHIFT & LCC_AHBIX_MD_M_VAL_MASK; + regval |= 252 << LCC_AHBIX_MD_NOT_2D_VAL_SHIFT & + LCC_AHBIX_MD_NOT_2D_VAL_MASK; + write32(&ahbix_regs->md, regval); + + regval = 0; + regval |= 253 << LCC_AHBIX_NS_N_VAL_SHIFT & LCC_AHBIX_NS_N_VAL_MASK; + regval |= LCC_AHBIX_NS_CRC_ENABLE; + regval |= LCC_AHBIX_NS_GFM_SEL_MNC; + regval |= LCC_AHBIX_NS_MNC_CLK_ENABLE; + regval |= LCC_AHBIX_NS_MNC_ENABLE; + regval |= LCC_AHBIX_NS_MNC_MODE_DUAL; + regval |= LCC_AHBIX_NS_PREDIV_BYPASS; + regval |= LCC_AHBIX_NS_MN_SRC_LPA; + write32(&ahbix_regs->ns, regval); + + mdelay(1); + + regval = read32(&ahbix_regs->status); + if (regval & LCC_AHBIX_STAT_AIF_CLK_MASK) + return 0; + + printk(BIOS_ERR, "%s: error enabling AHBIX clock\n", __func__); + return 1; +} + +static int lcc_init_mi2s(Ipq806xLccClocks *bus, unsigned freq) +{ + Ipq806xLccMi2sRegs *mi2s_regs = bus->lcc_mi2s_regs; + uint32_t regval; + uint8_t pd, m, n, d; + unsigned i; + + i = 0; + while (lcc_mi2s_freq_tbl[i].freq != 0) { + if (lcc_mi2s_freq_tbl[i].freq == freq) + break; + ++i; + } + if (lcc_mi2s_freq_tbl[i].freq == 0) { + printk(BIOS_ERR, "%s: invalid frequency given: %u\n", + __func__, freq); + return 1; + } + + switch (lcc_mi2s_freq_tbl[i].pd) { + case 1: + pd = LCC_MI2S_NS_PREDIV_BYPASS; + break; + case 2: + pd = LCC_MI2S_NS_PREDIV_DIV2; + break; + case 4: + pd = LCC_MI2S_NS_PREDIV_DIV4; + break; + default: + printk(BIOS_ERR, "%s: invalid prediv found: %u\n", __func__, + lcc_mi2s_freq_tbl[i].pd); + return 1; + } + + m = lcc_mi2s_freq_tbl[i].m; + n = ~(lcc_mi2s_freq_tbl[i].n - m); + d = ~(lcc_mi2s_freq_tbl[i].d * 2); + + regval = 0; + regval |= m << LCC_MI2S_MD_M_VAL_SHIFT & LCC_MI2S_MD_M_VAL_MASK; + regval |= d << LCC_MI2S_MD_NOT_2D_VAL_SHIFT & + LCC_MI2S_MD_NOT_2D_VAL_MASK; + write32(&mi2s_regs->md, regval); + + regval = 0; + regval |= n << LCC_MI2S_NS_N_VAL_SHIFT & LCC_MI2S_NS_N_VAL_MASK; + regval |= LCC_MI2S_NS_BIT_DIV_DIV4; + regval |= LCC_MI2S_NS_MNC_CLK_ENABLE; + regval |= LCC_MI2S_NS_MNC_ENABLE; + regval |= LCC_MI2S_NS_MNC_MODE_DUAL; + regval |= pd; + regval |= LCC_MI2S_NS_MN_SRC_LPA; + write32(&mi2s_regs->ns, regval); + + return 0; +} + +static int lcc_enable_mi2s(Ipq806xLccClocks *bus) +{ + Ipq806xLccMi2sRegs *mi2s_regs = bus->lcc_mi2s_regs; + uint32_t regval; + + regval = read32(&mi2s_regs->ns); + regval |= LCC_MI2S_NS_OSR_CXC_ENABLE; + regval |= LCC_MI2S_NS_BIT_CXC_ENABLE; + write32(&mi2s_regs->ns, regval); + + udelay(10); + + regval = read32(&mi2s_regs->status); + if (regval & LCC_MI2S_STAT_OSR_CLK_MASK) + if (regval & LCC_MI2S_STAT_BIT_CLK_MASK) + return 0; + + printk(BIOS_ERR, "%s: error enabling MI2S clocks: %u\n", + __func__, regval); + return 1; +} + +int audio_clock_config(unsigned frequency) +{ + Ipq806xLccClocks *bus = malloc(sizeof(*bus)); + + if (!bus) { + printk(BIOS_ERR, "%s: failed to allocate bus structure\n", + __func__); + return 1; + } + + bus->gcc_apcs_regs = (void *)(MSM_GCC_BASE + GCC_PLL_APCS_REG); + bus->lcc_pll0_regs = (void *)(MSM_LPASS_LCC_BASE + LCC_PLL0_MODE_REG); + bus->lcc_ahbix_regs = (void *)(MSM_LPASS_LCC_BASE + LCC_AHBIX_NS_REG); + bus->lcc_mi2s_regs = (void *)(MSM_LPASS_LCC_BASE + LCC_MI2S_NS_REG); + bus->lcc_pll_regs = (void *)(MSM_LPASS_LCC_BASE + LCC_PLL_PCLK_REG); + + + if (lcc_init_enable_pll0(bus)) + return 1; + if (lcc_init_enable_ahbix(bus)) + return 1; + if (lcc_init_mi2s(bus, frequency)) + return 1; + + if (lcc_enable_mi2s(bus)) + return 1; + + return 0; +} diff --git a/src/soc/qualcomm/ipq40xx/mbn_header.h b/src/soc/qualcomm/ipq40xx/mbn_header.h new file mode 100644 index 0000000000..cedcf12584 --- /dev/null +++ b/src/soc/qualcomm/ipq40xx/mbn_header.h @@ -0,0 +1,32 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2014 Google Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * 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. + */ + +#ifndef __SOC_QCA_IPQ40XX_MBN_HEADER_H__ +#define __SOC_QCA_IPQ40XX_MBN_HEADER_H__ + +#include <types.h> + +/* QCA firmware blob header gleaned from util/ipqheader/ipqheader.py */ + +struct mbn_header { + u32 mbn_type; + u32 mbn_version; + u32 mbn_source; + u32 mbn_destination; + u32 mbn_total_size; + u32 mbn_padding[5]; +}; + +#endif diff --git a/src/soc/qualcomm/ipq40xx/qup.c b/src/soc/qualcomm/ipq40xx/qup.c new file mode 100644 index 0000000000..c876d30c67 --- /dev/null +++ b/src/soc/qualcomm/ipq40xx/qup.c @@ -0,0 +1,480 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2014 - 2015 The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <arch/io.h> +#include <console/console.h> +#include <delay.h> +#include <soc/iomap.h> +#include <stdlib.h> +#include <soc/qup.h> + +#define TIMEOUT_CNT 100000 + +//TODO: refactor the following array to iomap driver. +static unsigned gsbi_qup_base[] = { + (unsigned)GSBI_QUP1_BASE, + (unsigned)GSBI_QUP2_BASE, + (unsigned)GSBI_QUP3_BASE, + (unsigned)GSBI_QUP4_BASE, + (unsigned)GSBI_QUP5_BASE, + (unsigned)GSBI_QUP6_BASE, + (unsigned)GSBI_QUP7_BASE, +}; + +#define QUP_ADDR(gsbi_num, reg) ((void *)((gsbi_qup_base[gsbi_num-1]) + (reg))) + +static qup_return_t qup_i2c_master_status(gsbi_id_t gsbi_id) +{ + uint32_t reg_val = read32(QUP_ADDR(gsbi_id, QUP_I2C_MASTER_STATUS)); + + if (read32(QUP_ADDR(gsbi_id, QUP_ERROR_FLAGS))) + return QUP_ERR_XFER_FAIL; + if (reg_val & QUP_I2C_INVALID_READ_ADDR) + return QUP_ERR_I2C_INVALID_SLAVE_ADDR; + if (reg_val & QUP_I2C_FAILED_MASK) + return QUP_ERR_I2C_FAILED; + if (reg_val & QUP_I2C_ARB_LOST) + return QUP_ERR_I2C_ARB_LOST; + if (reg_val & QUP_I2C_BUS_ERROR) + return QUP_ERR_I2C_BUS_ERROR; + if (reg_val & QUP_I2C_INVALID_WRITE) + return QUP_ERR_I2C_INVALID_WRITE; + if (reg_val & QUP_I2C_PACKET_NACK) + return QUP_ERR_I2C_NACK; + if (reg_val & QUP_I2C_INVALID_TAG) + return QUP_ERR_I2C_INVALID_TAG; + + return QUP_SUCCESS; +} + +static int check_bit_state(uint32_t *reg, int wait_for) +{ + unsigned int count = TIMEOUT_CNT; + + while ((read32(reg) & (QUP_STATE_VALID_MASK | QUP_STATE_MASK)) != + (QUP_STATE_VALID | wait_for)) { + if (count == 0) + return QUP_ERR_TIMEOUT; + count--; + udelay(1); + } + + return QUP_SUCCESS; +} + +/* + * Check whether GSBIn_QUP State is valid + */ +static qup_return_t qup_wait_for_state(gsbi_id_t gsbi_id, unsigned wait_for) +{ + return check_bit_state(QUP_ADDR(gsbi_id, QUP_STATE), wait_for); +} + +qup_return_t qup_reset_i2c_master_status(gsbi_id_t gsbi_id) +{ + /* + * Writing a one clears the status bits. + * Bit31-25, Bit1 and Bit0 are reserved. + */ + //TODO: Define each status bit. OR all status bits in a single macro. + write32(QUP_ADDR(gsbi_id, QUP_I2C_MASTER_STATUS), 0x3FFFFFC); + return QUP_SUCCESS; +} + +static qup_return_t qup_reset_master_status(gsbi_id_t gsbi_id) +{ + write32(QUP_ADDR(gsbi_id, QUP_ERROR_FLAGS), 0x7C); + write32(QUP_ADDR(gsbi_id, QUP_ERROR_FLAGS_EN), 0x7C); + qup_reset_i2c_master_status(gsbi_id); + return QUP_SUCCESS; +} + +static qup_return_t qup_fifo_wait_for(gsbi_id_t gsbi_id, uint32_t status) +{ + qup_return_t ret = QUP_ERR_UNDEFINED; + unsigned int count = TIMEOUT_CNT; + + while (!(read32(QUP_ADDR(gsbi_id, QUP_OPERATIONAL)) & status)) { + ret = qup_i2c_master_status(gsbi_id); + if (ret) + return ret; + if (count == 0) + return QUP_ERR_TIMEOUT; + count--; + } + + return QUP_SUCCESS; +} + +static qup_return_t qup_fifo_wait_while(gsbi_id_t gsbi_id, uint32_t status) +{ + qup_return_t ret = QUP_ERR_UNDEFINED; + unsigned int count = TIMEOUT_CNT; + + while (read32(QUP_ADDR(gsbi_id, QUP_OPERATIONAL)) & status) { + ret = qup_i2c_master_status(gsbi_id); + if (ret) + return ret; + if (count == 0) + return QUP_ERR_TIMEOUT; + count--; + } + + return QUP_SUCCESS; +} + +static qup_return_t qup_i2c_write_fifo(gsbi_id_t gsbi_id, qup_data_t *p_tx_obj, + uint8_t stop_seq) +{ + qup_return_t ret = QUP_ERR_UNDEFINED; + uint8_t addr = p_tx_obj->p.iic.addr; + uint8_t *data_ptr = p_tx_obj->p.iic.data; + unsigned data_len = p_tx_obj->p.iic.data_len; + unsigned idx = 0; + + qup_reset_master_status(gsbi_id); + qup_set_state(gsbi_id, QUP_STATE_RUN); + + write32(QUP_ADDR(gsbi_id, QUP_OUTPUT_FIFO), + (QUP_I2C_START_SEQ | QUP_I2C_ADDR(addr))); + + while (data_len) { + if (data_len == 1 && stop_seq) { + write32(QUP_ADDR(gsbi_id, QUP_OUTPUT_FIFO), + QUP_I2C_STOP_SEQ | QUP_I2C_DATA(data_ptr[idx])); + } else { + write32(QUP_ADDR(gsbi_id, QUP_OUTPUT_FIFO), + QUP_I2C_DATA_SEQ | QUP_I2C_DATA(data_ptr[idx])); + } + data_len--; + idx++; + if (data_len) { + ret = qup_fifo_wait_while(gsbi_id, OUTPUT_FIFO_FULL); + if (ret) + return ret; + } + /* Hardware sets the OUTPUT_SERVICE_FLAG flag to 1 when + OUTPUT_FIFO_NOT_EMPTY flag in the QUP_OPERATIONAL + register changes from 1 to 0, indicating that software + can write more data to the output FIFO. Software should + set OUTPUT_SERVICE_FLAG to 1 to clear it to 0, which + means that software knows to return to fill the output + FIFO with data. + */ + if (read32(QUP_ADDR(gsbi_id, QUP_OPERATIONAL)) & + OUTPUT_SERVICE_FLAG) { + write32(QUP_ADDR(gsbi_id, QUP_OPERATIONAL), + OUTPUT_SERVICE_FLAG); + } + } + + ret = qup_fifo_wait_while(gsbi_id, OUTPUT_FIFO_NOT_EMPTY); + if (ret) + return ret; + + qup_set_state(gsbi_id, QUP_STATE_PAUSE); + return qup_i2c_master_status(gsbi_id); +} + +static qup_return_t qup_i2c_write(gsbi_id_t gsbi_id, uint8_t mode, + qup_data_t *p_tx_obj, uint8_t stop_seq) +{ + qup_return_t ret = QUP_ERR_UNDEFINED; + + switch (mode) { + case QUP_MODE_FIFO: + ret = qup_i2c_write_fifo(gsbi_id, p_tx_obj, stop_seq); + break; + default: + ret = QUP_ERR_UNSUPPORTED; + } + + if (ret) { + qup_set_state(gsbi_id, QUP_STATE_RESET); + printk(BIOS_ERR, "%s() failed (%d)\n", __func__, ret); + } + + return ret; +} + +static qup_return_t qup_i2c_read_fifo(gsbi_id_t gsbi_id, qup_data_t *p_tx_obj) +{ + qup_return_t ret = QUP_ERR_UNDEFINED; + uint8_t addr = p_tx_obj->p.iic.addr; + uint8_t *data_ptr = p_tx_obj->p.iic.data; + unsigned data_len = p_tx_obj->p.iic.data_len; + unsigned idx = 0; + + qup_reset_master_status(gsbi_id); + qup_set_state(gsbi_id, QUP_STATE_RUN); + + write32(QUP_ADDR(gsbi_id, QUP_OUTPUT_FIFO), + QUP_I2C_START_SEQ | (QUP_I2C_ADDR(addr) | QUP_I2C_SLAVE_READ)); + + write32(QUP_ADDR(gsbi_id, QUP_OUTPUT_FIFO), + QUP_I2C_RECV_SEQ | data_len); + + ret = qup_fifo_wait_while(gsbi_id, OUTPUT_FIFO_NOT_EMPTY); + if (ret) + return ret; + + write32(QUP_ADDR(gsbi_id, QUP_OPERATIONAL), OUTPUT_SERVICE_FLAG); + + while (data_len) { + uint32_t data; + + ret = qup_fifo_wait_for(gsbi_id, INPUT_SERVICE_FLAG); + if (ret) + return ret; + + data = read32(QUP_ADDR(gsbi_id, QUP_INPUT_FIFO)); + + /* + * Process tag and corresponding data value. For I2C master + * mini-core, data in FIFO is composed of 16 bits and is divided + * into an 8-bit tag for the upper bits and 8-bit data for the + * lower bits. The 8-bit tag indicates whether the byte is the + * last byte, or if a bus error happened during the receipt of + * the byte. + */ + if ((QUP_I2C_MI_TAG(data)) == QUP_I2C_MIDATA_SEQ) { + /* Tag: MIDATA = Master input data.*/ + data_ptr[idx] = QUP_I2C_DATA(data); + idx++; + data_len--; + write32(QUP_ADDR(gsbi_id, QUP_OPERATIONAL), + INPUT_SERVICE_FLAG); + } else { + if (QUP_I2C_MI_TAG(data) == QUP_I2C_MISTOP_SEQ) { + /* Tag: MISTOP: Last byte of master input. */ + data_ptr[idx] = QUP_I2C_DATA(data); + idx++; + data_len--; + break; + } + /* Tag: MINACK: Invalid master input data.*/ + break; + } + } + + write32(QUP_ADDR(gsbi_id, QUP_OPERATIONAL), INPUT_SERVICE_FLAG); + p_tx_obj->p.iic.data_len = idx; + qup_set_state(gsbi_id, QUP_STATE_PAUSE); + + return QUP_SUCCESS; +} + +static qup_return_t qup_i2c_read(gsbi_id_t gsbi_id, uint8_t mode, + qup_data_t *p_tx_obj) +{ + qup_return_t ret = QUP_ERR_UNDEFINED; + + switch (mode) { + case QUP_MODE_FIFO: + ret = qup_i2c_read_fifo(gsbi_id, p_tx_obj); + break; + default: + ret = QUP_ERR_UNSUPPORTED; + } + + if (ret) { + qup_set_state(gsbi_id, QUP_STATE_RESET); + printk(BIOS_ERR, "%s() failed (%d)\n", __func__, ret); + } + + return ret; +} + +qup_return_t qup_init(gsbi_id_t gsbi_id, const qup_config_t *config_ptr) +{ + qup_return_t ret = QUP_ERR_UNDEFINED; + uint32_t reg_val; + + /* Reset the QUP core.*/ + write32(QUP_ADDR(gsbi_id, QUP_SW_RESET), 0x1); + + /*Wait till the reset takes effect */ + ret = qup_wait_for_state(gsbi_id, QUP_STATE_RESET); + if (ret) + goto bailout; + + /* Reset the config */ + write32(QUP_ADDR(gsbi_id, QUP_CONFIG), 0); + + /*Program the config register*/ + /*Set N value*/ + reg_val = 0x0F; + /*Set protocol*/ + switch (config_ptr->protocol) { + case QUP_MINICORE_I2C_MASTER: + reg_val |= ((config_ptr->protocol & + QUP_MINI_CORE_PROTO_MASK) << + QUP_MINI_CORE_PROTO_SHFT); + break; + default: + ret = QUP_ERR_UNSUPPORTED; + goto bailout; + } + write32(QUP_ADDR(gsbi_id, QUP_CONFIG), reg_val); + + /*Reset i2c clk cntl register*/ + write32(QUP_ADDR(gsbi_id, QUP_I2C_MASTER_CLK_CTL), 0); + + /*Set QUP IO Mode*/ + switch (config_ptr->mode) { + case QUP_MODE_FIFO: + reg_val = QUP_OUTPUT_BIT_SHIFT_EN | + ((config_ptr->mode & QUP_MODE_MASK) << + QUP_OUTPUT_MODE_SHFT) | + ((config_ptr->mode & QUP_MODE_MASK) << + QUP_INPUT_MODE_SHFT); + break; + default: + ret = QUP_ERR_UNSUPPORTED; + goto bailout; + } + write32(QUP_ADDR(gsbi_id, QUP_IO_MODES), reg_val); + + /*Set i2c clk cntl*/ + reg_val = (QUP_DIVIDER_MIN_VAL << QUP_HS_DIVIDER_SHFT); + reg_val |= ((((config_ptr->src_frequency / config_ptr->clk_frequency) + / 2) - QUP_DIVIDER_MIN_VAL) & + QUP_FS_DIVIDER_MASK); + write32(QUP_ADDR(gsbi_id, QUP_I2C_MASTER_CLK_CTL), reg_val); + +bailout: + if (ret) + printk(BIOS_ERR, "failed to init qup (%d)\n", ret); + + return ret; +} + +qup_return_t qup_set_state(gsbi_id_t gsbi_id, uint32_t state) +{ + qup_return_t ret = QUP_ERR_UNDEFINED; + unsigned curr_state = read32(QUP_ADDR(gsbi_id, QUP_STATE)); + + if ((state >= QUP_STATE_RESET && state <= QUP_STATE_PAUSE) + && (curr_state & QUP_STATE_VALID_MASK)) { + /* + * For PAUSE_STATE to RESET_STATE transition, + * two writes of 10[binary]) are required for the + * transition to complete. + */ + if (QUP_STATE_PAUSE == curr_state && QUP_STATE_RESET == state) { + write32(QUP_ADDR(gsbi_id, QUP_STATE), 0x2); + write32(QUP_ADDR(gsbi_id, QUP_STATE), 0x2); + } else { + write32(QUP_ADDR(gsbi_id, QUP_STATE), state); + } + ret = qup_wait_for_state(gsbi_id, state); + } + + return ret; +} + +static qup_return_t qup_i2c_send_data(gsbi_id_t gsbi_id, qup_data_t *p_tx_obj, + uint8_t stop_seq) +{ + qup_return_t ret = QUP_ERR_UNDEFINED; + uint8_t mode = (read32(QUP_ADDR(gsbi_id, QUP_IO_MODES)) >> + QUP_OUTPUT_MODE_SHFT) & QUP_MODE_MASK; + + ret = qup_i2c_write(gsbi_id, mode, p_tx_obj, stop_seq); + if (0) { + int i; + + printk(BIOS_DEBUG, "i2c tx bus %d device %2.2x:", + gsbi_id, p_tx_obj->p.iic.addr); + for (i = 0; i < p_tx_obj->p.iic.data_len; i++) + printk(BIOS_DEBUG, " %2.2x", p_tx_obj->p.iic.data[i]); + printk(BIOS_DEBUG, "\n"); + } + + return ret; +} + +qup_return_t qup_send_data(gsbi_id_t gsbi_id, qup_data_t *p_tx_obj, + uint8_t stop_seq) +{ + qup_return_t ret = QUP_ERR_UNDEFINED; + + if (p_tx_obj->protocol == ((read32(QUP_ADDR(gsbi_id, QUP_CONFIG)) >> + QUP_MINI_CORE_PROTO_SHFT) & QUP_MINI_CORE_PROTO_MASK)) { + switch (p_tx_obj->protocol) { + case QUP_MINICORE_I2C_MASTER: + ret = qup_i2c_send_data(gsbi_id, p_tx_obj, stop_seq); + break; + default: + ret = QUP_ERR_UNSUPPORTED; + } + } + + return ret; +} + +static qup_return_t qup_i2c_recv_data(gsbi_id_t gsbi_id, qup_data_t *p_rx_obj) +{ + qup_return_t ret = QUP_ERR_UNDEFINED; + uint8_t mode = (read32(QUP_ADDR(gsbi_id, QUP_IO_MODES)) >> + QUP_INPUT_MODE_SHFT) & QUP_MODE_MASK; + + ret = qup_i2c_read(gsbi_id, mode, p_rx_obj); + if (0) { + int i; + + printk(BIOS_DEBUG, "i2c rxed on bus %d device %2.2x:", + gsbi_id, p_rx_obj->p.iic.addr); + for (i = 0; i < p_rx_obj->p.iic.data_len; i++) + printk(BIOS_DEBUG, " %2.2x", p_rx_obj->p.iic.data[i]); + printk(BIOS_DEBUG, "\n"); + } + + return ret; +} + +qup_return_t qup_recv_data(gsbi_id_t gsbi_id, qup_data_t *p_rx_obj) +{ + qup_return_t ret = QUP_ERR_UNDEFINED; + + if (p_rx_obj->protocol == ((read32(QUP_ADDR(gsbi_id, QUP_CONFIG)) >> + QUP_MINI_CORE_PROTO_SHFT) & QUP_MINI_CORE_PROTO_MASK)) { + switch (p_rx_obj->protocol) { + case QUP_MINICORE_I2C_MASTER: + ret = qup_i2c_recv_data(gsbi_id, p_rx_obj); + break; + default: + ret = QUP_ERR_UNSUPPORTED; + } + } + + return ret; +} diff --git a/src/soc/qualcomm/ipq40xx/soc.c b/src/soc/qualcomm/ipq40xx/soc.c new file mode 100644 index 0000000000..201e9bc9fe --- /dev/null +++ b/src/soc/qualcomm/ipq40xx/soc.c @@ -0,0 +1,57 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007-2009 coresystems GmbH + * Copyright (C) 2011 The ChromiumOS Authors. All rights reserved. + * Copyright 2013 Google Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * 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 <console/console.h> +#include <device/device.h> +#include <symbols.h> +#include <soc/ipq_uart.h> + +#define RESERVED_SIZE_KB (0x01500000 / KiB) + +static void soc_read_resources(device_t dev) +{ + /* Reserve bottom 0x150_0000 bytes for NSS, SMEM, etc. */ + reserved_ram_resource(dev, 0, (uintptr_t)_dram / KiB, RESERVED_SIZE_KB); + ram_resource(dev, 0, (uintptr_t)_dram / KiB + RESERVED_SIZE_KB, + (CONFIG_DRAM_SIZE_MB * KiB) - RESERVED_SIZE_KB); +} + +static void soc_init(device_t dev) +{ + /* + * Do this in case console is not enabled: kernel's earlyprintk() + * should work no matter what the firmware console configuration is. + */ + ipq40xx_uart_init(); + + printk(BIOS_INFO, "CPU: QCA 40xx\n"); +} + +static struct device_operations soc_ops = { + .read_resources = soc_read_resources, + .init = soc_init, +}; + +static void enable_soc_dev(device_t dev) +{ + dev->ops = &soc_ops; +} + +struct chip_operations soc_qualcomm_ipq40xx_ops = { + CHIP_NAME("SOC QCA 40xx") + .enable_dev = enable_soc_dev, +}; diff --git a/src/soc/qualcomm/ipq40xx/spi.c b/src/soc/qualcomm/ipq40xx/spi.c new file mode 100644 index 0000000000..be98fba665 --- /dev/null +++ b/src/soc/qualcomm/ipq40xx/spi.c @@ -0,0 +1,805 @@ +/* + * Copyright (c) 2012 The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <arch/io.h> +#include <delay.h> +#include <gpio.h> +#include <soc/iomap.h> +#include <soc/spi.h> +#include <stdlib.h> +#include <string.h> + +#define SUCCESS 0 + +#define DUMMY_DATA_VAL 0 +#define TIMEOUT_CNT 100 +#define CS_ASSERT 1 +#define CS_DEASSERT 0 +#define NUM_PORTS 3 +#define NUM_GSBI_PINS 3 +#define TLMM_ARGS 6 +#define NUM_CS 4 +#define GSBI_PIN_IDX 0 +#define FUNC_SEL_IDX 1 +#define GPIO_DIR_IDX 2 +#define PULL_CONF_IDX 3 +#define DRV_STR_IDX 4 +#define GPIO_EN_IDX 5 + +/* Arbitrarily assigned error code values */ +#define ETIMEDOUT -10 +#define EINVAL -11 +#define EIO -12 + +#define GSBI_IDX_TO_GSBI(idx) (idx + 5) + + +/* MX_INPUT_COUNT and MX_OUTPUT_COUNT are 16-bits. Zero has a special meaning + * (count function disabled) and does not hold significance in the count. */ +#define MAX_PACKET_COUNT ((64 * KiB) - 1) + +/* + * TLMM Configuration for SPI NOR + * gsbi_pin_conf[bus_num][GPIO_NUM, FUNC_SEL, I/O, + * PULL UP/DOWN, DRV_STR, GPIO_FUNC] + * gsbi_pin_conf[0][x][y] -- GSBI5 + * gsbi_pin_conf[1][x][y] -- GSBI6 + * gsbi_pin_conf[2][x][y] -- GSBI7 +*/ +static unsigned int gsbi_pin_conf[NUM_PORTS][NUM_GSBI_PINS][TLMM_ARGS] = { + { + /* GSBI5 CLK */ + { + GSBI5_SPI_CLK, FUNC_SEL_1, GPIO_INPUT, + GPIO_PULL_DOWN, GPIO_DRV_STR_11MA, GPIO_FUNC_DISABLE + }, + /* GSBI5 MISO */ + { + GSBI5_SPI_MISO, FUNC_SEL_1, GPIO_INPUT, + GPIO_PULL_DOWN, GPIO_DRV_STR_10MA, GPIO_FUNC_DISABLE + }, + /* GSBI5 MOSI */ + { + GSBI5_SPI_MOSI, FUNC_SEL_1, GPIO_INPUT, + GPIO_PULL_DOWN, GPIO_DRV_STR_10MA, GPIO_FUNC_DISABLE + } + }, + { + /* GSBI6 CLK */ + { + GSBI6_SPI_CLK, FUNC_SEL_3, GPIO_INPUT, + GPIO_PULL_DOWN, GPIO_DRV_STR_11MA, GPIO_FUNC_DISABLE + }, + /* GSBI6 MISO */ + { + GSBI6_SPI_MISO, FUNC_SEL_3, GPIO_INPUT, + GPIO_PULL_DOWN, GPIO_DRV_STR_10MA, GPIO_FUNC_DISABLE + }, + /* GSBI6 MOSI */ + { + GSBI6_SPI_MOSI, FUNC_SEL_3, GPIO_INPUT, + GPIO_PULL_DOWN, GPIO_DRV_STR_10MA, GPIO_FUNC_DISABLE + } + }, + { + /* GSBI7 CLK */ + { + GSBI7_SPI_CLK, FUNC_SEL_1, GPIO_INPUT, + GPIO_PULL_DOWN, GPIO_DRV_STR_11MA, GPIO_FUNC_DISABLE + }, + /* GSBI7 MISO */ + { + GSBI7_SPI_MISO, FUNC_SEL_1, GPIO_INPUT, + GPIO_PULL_DOWN, GPIO_DRV_STR_10MA, GPIO_FUNC_DISABLE + }, + /* GSBI7 MOSI */ + { + GSBI7_SPI_MOSI, FUNC_SEL_1, GPIO_INPUT, + GPIO_PULL_DOWN, GPIO_DRV_STR_10MA, GPIO_FUNC_DISABLE + } + } +}; + +/* + * CS GPIO number array cs_gpio_array[port_num][cs_num] + * cs_gpio_array[0][x] -- GSBI5 + * cs_gpio_array[1][x] -- GSBI6 + * cs_gpio_array[2][x] -- GSBI7 + */ +static unsigned int cs_gpio_array[NUM_PORTS][NUM_CS] = { + { + GSBI5_SPI_CS_0, GSBI5_SPI_CS_1, GSBI5_SPI_CS_2, GSBI5_SPI_CS_3 + }, + { + GSBI6_SPI_CS_0, 0, 0, 0 + }, + { + GSBI7_SPI_CS_0, 0, 0, 0 + } +}; + +/* + * GSBI HCLK state register bit + * hclk_state[0] -- GSBI5 + * hclk_state[1] -- GSBI6 + * hclk_state[2] -- GSBI7 +*/ +static unsigned int hclk_state[NUM_PORTS] = { + GSBI5_HCLK, + GSBI6_HCLK, + GSBI7_HCLK +}; + +/* + * GSBI QUP_APPS_CLK state register bit + * qup_apps_clk_state[0] -- GSBI5 + * qup_apps_clk_state[1] -- GSBI6 + * qup_apps_clk_state[2] -- GSBI7 +*/ +static unsigned int qup_apps_clk_state[NUM_PORTS] = { + GSBI5_QUP_APPS_CLK, + GSBI6_QUP_APPS_CLK, + GSBI7_QUP_APPS_CLK +}; + + +static int check_bit_state(uint32_t reg_addr, int bit_num, + int val, int us_delay) +{ + unsigned int count = TIMEOUT_CNT; + unsigned int bit_val = ((readl_i(reg_addr) >> bit_num) & 0x01); + + while (bit_val != val) { + count--; + if (count == 0) + return -ETIMEDOUT; + udelay(us_delay); + bit_val = ((readl_i(reg_addr) >> bit_num) & 0x01); + } + + return SUCCESS; +} + +/* + * Check whether GSBIn_QUP State is valid + */ +static int check_qup_state_valid(struct ipq_spi_slave *ds) +{ + + return check_bit_state(ds->regs->qup_state, QUP_STATE_VALID_BIT, + QUP_STATE_VALID, 1); + +} + +/* + * Configure GSBIn Core state + */ +static int config_spi_state(struct ipq_spi_slave *ds, unsigned int state) +{ + uint32_t val; + int ret; + uint32_t new_state; + + ret = check_qup_state_valid(ds); + if (ret != SUCCESS) + return ret; + + switch (state) { + case SPI_RUN_STATE: + new_state = QUP_STATE_RUN_STATE; + break; + + case SPI_RESET_STATE: + new_state = QUP_STATE_RESET_STATE; + break; + + case SPI_PAUSE_STATE: + new_state = QUP_STATE_PAUSE_STATE; + break; + + default: + printk(BIOS_ERR, + "err: unsupported GSBI SPI state : %d\n", state); + return -EINVAL; + } + + /* Set the state as requested */ + val = (readl_i(ds->regs->qup_state) & ~QUP_STATE_MASK) + | new_state; + writel_i(val, ds->regs->qup_state); + return check_qup_state_valid(ds); +} + +/* + * Set GSBIn SPI Mode + */ +static void spi_set_mode(struct ipq_spi_slave *ds, unsigned int mode) +{ + unsigned int clk_idle_state; + unsigned int input_first_mode; + uint32_t val; + + switch (mode) { + case GSBI_SPI_MODE_0: + clk_idle_state = 0; + input_first_mode = SPI_INPUT_FIRST_MODE; + break; + case GSBI_SPI_MODE_1: + clk_idle_state = 0; + input_first_mode = 0; + break; + case GSBI_SPI_MODE_2: + clk_idle_state = 1; + input_first_mode = SPI_INPUT_FIRST_MODE; + break; + case GSBI_SPI_MODE_3: + clk_idle_state = 1; + input_first_mode = 0; + break; + default: + printk(BIOS_ERR, + "err : unsupported spi mode : %d\n", mode); + return; + } + + val = readl_i(ds->regs->spi_config); + val |= input_first_mode; + writel_i(val, ds->regs->spi_config); + + val = readl_i(ds->regs->io_control); + if (clk_idle_state) + val |= SPI_IO_CONTROL_CLOCK_IDLE_HIGH; + else + val &= ~SPI_IO_CONTROL_CLOCK_IDLE_HIGH; + + writel_i(val, ds->regs->io_control); +} + +/* + * Check for HCLK state + */ +static int check_hclk_state(unsigned int core_num, int enable) +{ + return check_bit_state(CLK_HALT_CFPB_STATEB_REG, + hclk_state[core_num], enable, 5); +} + +/* + * Check for QUP APPS CLK state + */ +static int check_qup_clk_state(unsigned int core_num, int enable) +{ + return check_bit_state(CLK_HALT_CFPB_STATEB_REG, + qup_apps_clk_state[core_num], enable, 5); +} + +/* + * Function to assert and De-assert chip select + */ +static void CS_change(int port_num, int cs_num, int enable) +{ + unsigned int cs_gpio = cs_gpio_array[port_num][cs_num]; + void *addr = GPIO_IN_OUT_ADDR(cs_gpio); + uint32_t val = readl_i(addr); + + val &= (~(1 << GPIO_OUTPUT)); + if (!enable) + val |= (1 << GPIO_OUTPUT); + write32(addr, val); +} + +/* + * GSBIn TLMM configuration + */ +static void gsbi_pin_config(unsigned int port_num, int cs_num) +{ + unsigned int gpio; + unsigned int i; + /* Hold the GSBIn (core_num) core in reset */ + clrsetbits_le32_i(GSBIn_RESET_REG(GSBI_IDX_TO_GSBI(port_num)), + GSBI1_RESET_MSK, GSBI1_RESET); + + /* + * Configure SPI_CLK, SPI_MISO and SPI_MOSI + */ + for (i = 0; i < NUM_GSBI_PINS; i++) { + unsigned int func_sel; + unsigned int io_config; + unsigned int pull_config; + unsigned int drv_strength; + unsigned int gpio_en; + unsigned int *ptr; + + ptr = gsbi_pin_conf[port_num][i]; + gpio = *(ptr + GSBI_PIN_IDX); + func_sel = *(ptr + FUNC_SEL_IDX); + io_config = *(ptr + GPIO_DIR_IDX); + pull_config = *(ptr + PULL_CONF_IDX); + drv_strength = *(ptr + DRV_STR_IDX); + gpio_en = *(ptr + GPIO_EN_IDX); + + gpio_tlmm_config(gpio, func_sel, io_config, + pull_config, drv_strength, gpio_en); + } + + gpio = cs_gpio_array[port_num][cs_num]; + /* configure CS */ + gpio_tlmm_config(gpio, FUNC_SEL_GPIO, GPIO_OUTPUT, GPIO_PULL_UP, + GPIO_DRV_STR_10MA, GPIO_FUNC_ENABLE); + CS_change(port_num, cs_num, CS_DEASSERT); +} + +/* + * Clock configuration for GSBIn Core + */ +static int gsbi_clock_init(struct ipq_spi_slave *ds) +{ + int ret; + + /* Hold the GSBIn (core_num) core in reset */ + clrsetbits_le32_i(GSBIn_RESET_REG(GSBI_IDX_TO_GSBI(ds->slave.bus)), + GSBI1_RESET_MSK, GSBI1_RESET); + + /* Disable GSBIn (core_num) QUP core clock branch */ + clrsetbits_le32_i(ds->regs->qup_ns_reg, QUP_CLK_BRANCH_ENA_MSK, + QUP_CLK_BRANCH_DIS); + + ret = check_qup_clk_state(ds->slave.bus, 1); + if (ret) { + printk(BIOS_ERR, + "QUP Clock Halt For GSBI%d failed!\n", ds->slave.bus); + return ret; + } + + /* Disable M/N:D counter and hold M/N:D counter in reset */ + clrsetbits_le32_i(ds->regs->qup_ns_reg, (MNCNTR_MSK | MNCNTR_RST_MSK), + (MNCNTR_RST_ENA | MNCNTR_DIS)); + + /* Disable GSBIn (core_num) QUP core clock root */ + clrsetbits_le32_i(ds->regs->qup_ns_reg, CLK_ROOT_ENA_MSK, CLK_ROOT_DIS); + + clrsetbits_le32_i(ds->regs->qup_ns_reg, GSBIn_PLL_SRC_MSK, + GSBIn_PLL_SRC_PLL8); + clrsetbits_le32_i(ds->regs->qup_ns_reg, GSBIn_PRE_DIV_SEL_MSK, + (0 << GSBI_PRE_DIV_SEL_SHFT)); + + /* Program M/N:D values for GSBIn_QUP_APPS_CLK @50MHz */ + clrsetbits_le32_i(ds->regs->qup_md_reg, GSBIn_M_VAL_MSK, + (0x01 << GSBI_M_VAL_SHFT)); + clrsetbits_le32_i(ds->regs->qup_md_reg, GSBIn_D_VAL_MSK, + (0xF7 << GSBI_D_VAL_SHFT)); + clrsetbits_le32_i(ds->regs->qup_ns_reg, GSBIn_N_VAL_MSK, + (0xF8 << GSBI_N_VAL_SHFT)); + + /* Set MNCNTR_MODE = 0: Bypass mode */ + clrsetbits_le32_i(ds->regs->qup_ns_reg, MNCNTR_MODE_MSK, + MNCNTR_MODE_DUAL_EDGE); + + /* De-assert the M/N:D counter reset */ + clrsetbits_le32_i(ds->regs->qup_ns_reg, MNCNTR_RST_MSK, MNCNTR_RST_DIS); + clrsetbits_le32_i(ds->regs->qup_ns_reg, MNCNTR_MSK, MNCNTR_EN); + + /* + * Enable the GSBIn (core_num) QUP core clock root. + * Keep MND counter disabled + */ + clrsetbits_le32_i(ds->regs->qup_ns_reg, CLK_ROOT_ENA_MSK, CLK_ROOT_ENA); + + /* Enable GSBIn (core_num) QUP core clock branch */ + clrsetbits_le32_i(ds->regs->qup_ns_reg, QUP_CLK_BRANCH_ENA_MSK, + QUP_CLK_BRANCH_ENA); + + ret = check_qup_clk_state(ds->slave.bus, 0); + if (ret) { + printk(BIOS_ERR, + "QUP Clock Enable For GSBI%d failed!\n", ds->slave.bus); + return ret; + } + + /* Enable GSBIn (core_num) core clock branch */ + clrsetbits_le32_i(GSBIn_HCLK_CTL_REG(GSBI_IDX_TO_GSBI(ds->slave.bus)), + GSBI_CLK_BRANCH_ENA_MSK, GSBI_CLK_BRANCH_ENA); + + ret = check_hclk_state(ds->slave.bus, 0); + if (ret) { + printk(BIOS_ERR, + "HCLK Enable For GSBI%d failed!\n", ds->slave.bus); + return ret; + } + + /* Release GSBIn (core_num) core from reset */ + clrsetbits_le32_i(GSBIn_RESET_REG(GSBI_IDX_TO_GSBI(ds->slave.bus)), + GSBI1_RESET_MSK, 0); + udelay(50); + + return SUCCESS; +} + +/* + * Reset entire QUP and all mini cores + */ +static void spi_reset(struct ipq_spi_slave *ds) +{ + writel_i(0x1, ds->regs->qup_sw_reset); + udelay(5); +} + +static const struct gsbi_spi spi_reg[] = { + /* GSBI5 registers for SPI interface */ + { + GSBI5_SPI_CONFIG_REG, + GSBI5_SPI_IO_CONTROL_REG, + GSBI5_SPI_ERROR_FLAGS_REG, + GSBI5_SPI_ERROR_FLAGS_EN_REG, + GSBI5_GSBI_CTRL_REG_REG, + GSBI5_QUP_CONFIG_REG, + GSBI5_QUP_ERROR_FLAGS_REG, + GSBI5_QUP_ERROR_FLAGS_EN_REG, + GSBI5_QUP_OPERATIONAL_REG, + GSBI5_QUP_IO_MODES_REG, + GSBI5_QUP_STATE_REG, + GSBI5_QUP_INPUT_FIFOc_REG(0), + GSBI5_QUP_OUTPUT_FIFOc_REG(0), + GSBI5_QUP_MX_INPUT_COUNT_REG, + GSBI5_QUP_MX_OUTPUT_COUNT_REG, + GSBI5_QUP_SW_RESET_REG, + GSBIn_QUP_APPS_NS_REG(5), + GSBIn_QUP_APPS_MD_REG(5), + }, + /* GSBI6 registers for SPI interface */ + { + GSBI6_SPI_CONFIG_REG, + GSBI6_SPI_IO_CONTROL_REG, + GSBI6_SPI_ERROR_FLAGS_REG, + GSBI6_SPI_ERROR_FLAGS_EN_REG, + GSBI6_GSBI_CTRL_REG_REG, + GSBI6_QUP_CONFIG_REG, + GSBI6_QUP_ERROR_FLAGS_REG, + GSBI6_QUP_ERROR_FLAGS_EN_REG, + GSBI6_QUP_OPERATIONAL_REG, + GSBI6_QUP_IO_MODES_REG, + GSBI6_QUP_STATE_REG, + GSBI6_QUP_INPUT_FIFOc_REG(0), + GSBI6_QUP_OUTPUT_FIFOc_REG(0), + GSBI6_QUP_MX_INPUT_COUNT_REG, + GSBI6_QUP_MX_OUTPUT_COUNT_REG, + GSBI6_QUP_SW_RESET_REG, + GSBIn_QUP_APPS_NS_REG(6), + GSBIn_QUP_APPS_MD_REG(6), + }, + /* GSBI7 registers for SPI interface */ + { + GSBI7_SPI_CONFIG_REG, + GSBI7_SPI_IO_CONTROL_REG, + GSBI7_SPI_ERROR_FLAGS_REG, + GSBI7_SPI_ERROR_FLAGS_EN_REG, + GSBI7_GSBI_CTRL_REG_REG, + GSBI7_QUP_CONFIG_REG, + GSBI7_QUP_ERROR_FLAGS_REG, + GSBI7_QUP_ERROR_FLAGS_EN_REG, + GSBI7_QUP_OPERATIONAL_REG, + GSBI7_QUP_IO_MODES_REG, + GSBI7_QUP_STATE_REG, + GSBI7_QUP_INPUT_FIFOc_REG(0), + GSBI7_QUP_OUTPUT_FIFOc_REG(0), + GSBI7_QUP_MX_INPUT_COUNT_REG, + GSBI7_QUP_MX_OUTPUT_COUNT_REG, + GSBI7_QUP_SW_RESET_REG, + GSBIn_QUP_APPS_NS_REG(7), + GSBIn_QUP_APPS_MD_REG(7), + } +}; +static struct ipq_spi_slave spi_slave_pool[2]; + +void spi_init(void) +{ + /* just in case */ + memset(spi_slave_pool, 0, sizeof(spi_slave_pool)); +} + +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs) +{ + struct ipq_spi_slave *ds = NULL; + int i; + + /* + * IPQ GSBI (Generic Serial Bus Interface) supports SPI Flash + * on different GSBI5, GSBI6 and GSBI7 + * with different number of chip selects (CS, channels): + */ + if ((bus < GSBI5_SPI) || (bus > GSBI7_SPI) + || ((bus == GSBI5_SPI) && (cs > 3)) + || ((bus == GSBI6_SPI) && (cs > 0)) + || ((bus == GSBI7_SPI) && (cs > 0))) { + printk(BIOS_ERR, "SPI error: unsupported bus %d (Supported busses 0,1 and 2) or chipselect\n", + bus); + } + + for (i = 0; i < ARRAY_SIZE(spi_slave_pool); i++) { + if (spi_slave_pool[i].allocated) + continue; + ds = spi_slave_pool + i; + ds->slave.bus = bus; + ds->slave.cs = cs; + ds->regs = &spi_reg[bus]; + + /* + * TODO(vbendeb): + * hardcoded frequency and mode - we might need to find a way + * to configure this + */ + ds->freq = 10000000; + ds->mode = GSBI_SPI_MODE_0; + ds->allocated = 1; + + return &ds->slave; + } + + printk(BIOS_ERR, "SPI error: all %d pools busy\n", i); + return NULL; +} + +/* + * GSBIn SPI Hardware Initialisation + */ +static int spi_hw_init(struct ipq_spi_slave *ds) +{ + int ret; + + if (ds->initialized) + return 0; + + /* GSBI module configuration */ + spi_reset(ds); + + /* Set the GSBIn QUP state */ + ret = config_spi_state(ds, SPI_RESET_STATE); + if (ret) + return ret; + + /* Configure GSBI_CTRL register to set protocol_mode to SPI:011 */ + clrsetbits_le32_i(ds->regs->gsbi_ctrl, PROTOCOL_CODE_MSK, + PROTOCOL_CODE_SPI); + + /* + * Configure Mini core to SPI core with Input Output enabled, + * SPI master, N = 8 bits + */ + clrsetbits_le32_i(ds->regs->qup_config, (QUP_CONFIG_MINI_CORE_MSK | + SPI_QUP_CONF_INPUT_MSK | + SPI_QUP_CONF_OUTPUT_MSK | + SPI_BIT_WORD_MSK), + (QUP_CONFIG_MINI_CORE_SPI | + SPI_QUP_CONF_NO_INPUT | + SPI_QUP_CONF_NO_OUTPUT | + SPI_8_BIT_WORD)); + + /* + * Configure Input first SPI protocol, + * SPI master mode and no loopback + */ + clrsetbits_le32_i(ds->regs->spi_config, (LOOP_BACK_MSK | + SLAVE_OPERATION_MSK), + (NO_LOOP_BACK | + SLAVE_OPERATION)); + + /* + * Configure SPI IO Control Register + * CLK_ALWAYS_ON = 0 + * MX_CS_MODE = 0 + * NO_TRI_STATE = 1 + */ + writel_i((CLK_ALWAYS_ON | MX_CS_MODE | NO_TRI_STATE), + ds->regs->io_control); + + /* + * Configure SPI IO Modes. + * OUTPUT_BIT_SHIFT_EN = 1 + * INPUT_MODE = Block Mode + * OUTPUT MODE = Block Mode + */ + clrsetbits_le32_i(ds->regs->qup_io_modes, (OUTPUT_BIT_SHIFT_MSK | + INPUT_BLOCK_MODE_MSK | + OUTPUT_BLOCK_MODE_MSK), + (OUTPUT_BIT_SHIFT_EN | + INPUT_BLOCK_MODE | + OUTPUT_BLOCK_MODE)); + + spi_set_mode(ds, ds->mode); + + /* Disable Error mask */ + writel_i(0, ds->regs->error_flags_en); + writel_i(0, ds->regs->qup_error_flags_en); + + ds->initialized = 1; + + return SUCCESS; +} + +int spi_claim_bus(struct spi_slave *slave) +{ + struct ipq_spi_slave *ds = to_ipq_spi(slave); + unsigned int ret; + + if (ds->initialized) + return SUCCESS; + + /* GPIO Configuration for SPI port */ + gsbi_pin_config(ds->slave.bus, ds->slave.cs); + + /* Clock configuration */ + ret = gsbi_clock_init(ds); + if (ret) + return ret; + + ret = spi_hw_init(ds); + if (ret) + return -EIO; + + return SUCCESS; +} + +void spi_release_bus(struct spi_slave *slave) +{ + struct ipq_spi_slave *ds = to_ipq_spi(slave); + + /* Reset the SPI hardware */ + spi_reset(ds); + ds->initialized = 0; +} + +static int spi_xfer_tx_packet(struct ipq_spi_slave *ds, + const uint8_t *dout, unsigned out_bytes) +{ + int ret; + + writel_i(out_bytes, ds->regs->qup_mx_output_count); + + ret = config_spi_state(ds, SPI_RUN_STATE); + if (ret) + return ret; + + while (out_bytes) { + if (readl_i(ds->regs->qup_operational) & QUP_OUTPUT_FIFO_FULL) + continue; + + writel_i(*dout++, ds->regs->qup_output_fifo); + out_bytes--; + + /* Wait for output FIFO to drain. */ + if (!out_bytes) + while (readl_i(ds->regs->qup_operational) & + QUP_OUTPUT_FIFO_NOT_EMPTY) + ; + } + + return config_spi_state(ds, SPI_RESET_STATE); +} + +static int spi_xfer_rx_packet(struct ipq_spi_slave *ds, + uint8_t *din, unsigned in_bytes) +{ + int ret; + + writel_i(in_bytes, ds->regs->qup_mx_input_count); + writel_i(in_bytes, ds->regs->qup_mx_output_count); + + ret = config_spi_state(ds, SPI_RUN_STATE); + if (ret) + return ret; + + /* Seed clocking */ + writel_i(0xff, ds->regs->qup_output_fifo); + while (in_bytes) { + if (!(readl_i(ds->regs->qup_operational) & + QUP_INPUT_FIFO_NOT_EMPTY)) + continue; + /* Keep it clocking */ + writel_i(0xff, ds->regs->qup_output_fifo); + + *din++ = readl_i(ds->regs->qup_input_fifo) & 0xff; + in_bytes--; + } + + return config_spi_state(ds, SPI_RESET_STATE); +} + +unsigned int spi_crop_chunk(unsigned int cmd_len, unsigned int buf_len) +{ + return min(MAX_PACKET_COUNT, buf_len); +} + +int spi_xfer(struct spi_slave *slave, const void *dout, + unsigned out_bytes, void *din, unsigned in_bytes) +{ + int ret; + struct ipq_spi_slave *ds = to_ipq_spi(slave); + + /* Assert the chip select */ + CS_change(ds->slave.bus, ds->slave.cs, CS_ASSERT); + + ret = config_spi_state(ds, SPI_RESET_STATE); + if (ret) + goto out; + + if (!out_bytes) + goto spi_receive; + + /* + * Let's do the write side of the transaction first. Enable output + * FIFO. + */ + clrsetbits_le32_i(ds->regs->qup_config, SPI_QUP_CONF_OUTPUT_MSK, + SPI_QUP_CONF_OUTPUT_ENA); + + while (out_bytes) { + unsigned todo = MIN(out_bytes, MAX_PACKET_COUNT); + + ret = spi_xfer_tx_packet(ds, dout, todo); + if (ret) + break; + + out_bytes -= todo; + dout += todo; + } + + if (ret) + goto out; + +spi_receive: + if (!in_bytes) /* Nothing to read. */ + goto out; + + /* Enable input FIFO */ + clrsetbits_le32_i(ds->regs->qup_config, SPI_QUP_CONF_INPUT_MSK, + SPI_QUP_CONF_INPUT_ENA); + + while (in_bytes) { + unsigned todo = MIN(in_bytes, MAX_PACKET_COUNT); + + ret = spi_xfer_rx_packet(ds, din, todo); + if (ret) + break; + + in_bytes -= todo; + din += todo; + } + +out: + /* Deassert CS */ + CS_change(ds->slave.bus, ds->slave.cs, CS_DEASSERT); + + /* + * Put the SPI Core back in the Reset State + * to end the transfer + */ + (void)config_spi_state(ds, SPI_RESET_STATE); + + return ret; +} diff --git a/src/soc/qualcomm/ipq40xx/timer.c b/src/soc/qualcomm/ipq40xx/timer.c new file mode 100644 index 0000000000..7b8c1f0cf6 --- /dev/null +++ b/src/soc/qualcomm/ipq40xx/timer.c @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2011 - 2014 The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <delay.h> +#include <soc/iomap.h> +#include <soc/ipq_timer.h> +#include <timer.h> + +/* + * DGT runs at 25 MHz / 4, or 6.25 ticks per microsecond + */ +#define DGT_MHZ_NUM 25 +#define DGT_MHZ_DEN 4 + +#define TIMER_TICKS(us) ((DGT_MHZ_NUM*(us) + (DGT_MHZ_DEN - 1)) / DGT_MHZ_DEN) +#define TIMER_USECS(ticks) (DGT_MHZ_DEN*(ticks) / DGT_MHZ_NUM) + +/* Clock divider values for the timer. */ +#define DGT_CLK_DIV_1 0 +#define DGT_CLK_DIV_2 1 +#define DGT_CLK_DIV_3 2 +#define DGT_CLK_DIV_4 3 + +/** + * init_timer - initialize timer + */ +void init_timer(void) +{ + /* disable timer */ + writel_i(0, DGT_ENABLE); + + /* DGT uses TCXO source which is 25MHz. + * The timer should run at 1/4th the frequency of TCXO + * according to clock plan. + * Set clock divider to 4. + */ + writel_i(DGT_CLK_DIV_4, DGT_CLK_CTL); + + /* Enable timer */ + writel_i(0, DGT_CLEAR); + writel_i(DGT_ENABLE_EN, DGT_ENABLE); +} + +/** + * udelay - generates micro second delay. + * @param usec: delay duration in microseconds + */ +void udelay(unsigned usec) +{ + uint32_t now; + uint32_t last; + uint32_t ticks; + uint32_t curr_ticks = 0; + + /* Calculate number of ticks required. */ + ticks = TIMER_TICKS(usec); + + /* Obtain the current timer value. */ + last = readl_i(DGT_COUNT_VAL); + + /* Loop until the right number of ticks. */ + while (curr_ticks < ticks) { + now = readl_i(DGT_COUNT_VAL); + curr_ticks += now - last; + last = now; + } +} + +void timer_monotonic_get(struct mono_time *mt) +{ + mono_time_set_usecs(mt, TIMER_USECS(readl_i(DGT_COUNT_VAL))); +} diff --git a/src/soc/qualcomm/ipq40xx/tz_wrapper.S b/src/soc/qualcomm/ipq40xx/tz_wrapper.S new file mode 100644 index 0000000000..70cc170f64 --- /dev/null +++ b/src/soc/qualcomm/ipq40xx/tz_wrapper.S @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2014, 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. + */ + +/* + * TZ expects the ARM core to be in 'ARM' mode. However, coreboot seems + * to be compiled in mixed thumb/arm mode. Hence create a glue function + * to invoke TZ. + */ + +#include <arch/asm.h> + +/* + * Force ARM mode. Else this gets assembled with mixed ARM and + * Thumb instructions. We set up everything and jump to TZBSP + * using the 'blx' instruction. For 'blx' if the last bit of the + * destination address is zero, it switches to ARM mode. Since, + * we are already in ARM mode, nothing to switch as such. + * + * However, when TZBSP returns, the CPU is still in ARM mode. + * If the assembler inserts Thumb instructions between the point + * of return from TZBSP to the 'bx' instruction we are hosed. + * Hence forcing ARM mode. + * + * Rest of the code can be compiled in mixed ARM/Thumb mode. + * Since tz_init_wrapper is being forced as an ARM symbol, + * callers will use 'blx' to come here forcing a switch to + * ARM mode. The wrapper does its job and returns back to the + * Thumb caller. + */ +.arm +/* + * int tz_init_wrapper(int, int, void *); + */ +ENTRY(tz_init_wrapper) + .global tz_init_wrapper + + /* + * r0 = tz_arg1 + * r1 = tz_arg2 + * r2 = tz_load_addr + */ + + /* + * Per the AAPCS + * r0, r1, r2, r3, r12 can be clobbered + * r4, r5, r6, r7, r8, r9, r10, r11 have to be preserved + * + * Following code clobbers + * r0 - Setting return value to zero + * r1 - For doing a thumb return + * r3 - Passing 'SP' from current mode to 'svc' mode + * r4 - To save & restore CPSR + * + * Per AAPCS, save and restore r4, rest are 'clobberable' :) + * The invoked code takes care of saving and restoring the other + * preserved registers (i.e. r5 - r11) + * + * Stack Usage: + * SP -> | LR | (Lower address) + * | r4 | + * | CPSR | + * |-------| + * | . | + * | . | + * | . | (Higher address) + */ + + sub sp, sp, #12 /* Allocate stack frame */ + str lr, [sp] /* Save return address */ + str r4, [sp, #4] /* Use r4 to hold the new CPSR value */ + + mov r3, sp /* Get current stack pointer */ + + mrs r4, CPSR /* save CPSR */ + str r4, [sp, #8] + + bic r4, r4, 0x1f /* Clear mode bits */ + orr r4, r4, 0x13 /* 'svc' mode */ + msr cpsr_cxf, r4 /* Switch to Supervisor mode. */ + mov sp, r3 /* Use the same stack as the previous mode */ + + blx r2 /* Jump to TZ in ARM mode */ + + nop /* back from TZ, in ARM mode */ + + ldr r4, [sp, #8] /* restore CPSR */ + msr cpsr_cxf, r4 + + ldr r4, [sp, #4] /* restore r4 */ + + ldr lr, [sp] /* saved return address */ + add sp, sp, #12 /* free stack frame */ + + bx lr /* back to thumb caller */ + +ENDPROC(tz_init_wrapper) diff --git a/src/soc/qualcomm/ipq40xx/uart.c b/src/soc/qualcomm/ipq40xx/uart.c new file mode 100644 index 0000000000..99b2b055b7 --- /dev/null +++ b/src/soc/qualcomm/ipq40xx/uart.c @@ -0,0 +1,406 @@ +/* + * Copyright (c) 2012 The Linux Foundation. All rights reserved. + * Source : APQ8064 LK boot + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <arch/io.h> +#include <boot/coreboot_tables.h> +#include <console/console.h> +#include <console/uart.h> +#include <delay.h> +#include <gpio.h> +#include <soc/clock.h> +#include <soc/gsbi.h> +#include <soc/ipq_uart.h> +#include <stdint.h> +#include <stdlib.h> + +#define FIFO_DATA_SIZE 4 + +typedef struct { + void *uart_dm_base; + void *uart_gsbi_base; + unsigned uart_gsbi; + uart_clk_mnd_t mnd_value; + gpio_func_data_t dbg_uart_gpio[NO_OF_DBG_UART_GPIOS]; +} uart_params_t; + +/* + * All constants lifted from u-boot's + * board/qcom/ipq40xx_cdp/ipq40xx_board_param.h + */ +static const uart_params_t uart_board_param = { + .uart_dm_base = (void *)UART4_DM_BASE, + .uart_gsbi_base = (void *)UART_GSBI4_BASE, + .uart_gsbi = GSBI_4, + .mnd_value = { 12, 625, 313 }, + .dbg_uart_gpio = { + { + .gpio = 10, + .func = 1, + .dir = GPIO_OUTPUT, + .pull = GPIO_NO_PULL, + .drvstr = GPIO_12MA, + .enable = GPIO_DISABLE + }, + { + .gpio = 11, + .func = 1, + .dir = GPIO_INPUT, + .pull = GPIO_NO_PULL, + .drvstr = GPIO_12MA, + .enable = GPIO_DISABLE + }, + } +}; + +/** + * msm_boot_uart_dm_init_rx_transfer - Init Rx transfer + * @uart_dm_base: UART controller base address + */ +static unsigned int msm_boot_uart_dm_init_rx_transfer(void *uart_dm_base) +{ + /* Reset receiver */ + write32(MSM_BOOT_UART_DM_CR(uart_dm_base), + MSM_BOOT_UART_DM_CMD_RESET_RX); + + /* Enable receiver */ + write32(MSM_BOOT_UART_DM_CR(uart_dm_base), + MSM_BOOT_UART_DM_CR_RX_ENABLE); + write32(MSM_BOOT_UART_DM_DMRX(uart_dm_base), + MSM_BOOT_UART_DM_DMRX_DEF_VALUE); + + /* Clear stale event */ + write32(MSM_BOOT_UART_DM_CR(uart_dm_base), + MSM_BOOT_UART_DM_CMD_RES_STALE_INT); + + /* Enable stale event */ + write32(MSM_BOOT_UART_DM_CR(uart_dm_base), + MSM_BOOT_UART_DM_GCMD_ENA_STALE_EVT); + + return MSM_BOOT_UART_DM_E_SUCCESS; +} + +#if IS_ENABLED(CONFIG_DRIVERS_UART) +static unsigned int msm_boot_uart_dm_init(void *uart_dm_base); + +/* Received data is valid or not */ +static int valid_data = 0; + +/* Received data */ +static unsigned int word = 0; + +/** + * msm_boot_uart_dm_read - reads a word from the RX FIFO. + * @data: location where the read data is stored + * @count: no of valid data in the FIFO + * @wait: indicates blocking call or not blocking call + * + * Reads a word from the RX FIFO. If no data is available blocks if + * @wait is true, else returns %MSM_BOOT_UART_DM_E_RX_NOT_READY. + */ + #if 0 /* Not used yet */ +static unsigned int +msm_boot_uart_dm_read(unsigned int *data, int *count, int wait) +{ + static int total_rx_data = 0; + static int rx_data_read = 0; + void *base; + uint32_t status_reg; + + base = uart_board_param.uart_dm_base; + + if (data == NULL) + return MSM_BOOT_UART_DM_E_INVAL; + + status_reg = readl(MSM_BOOT_UART_DM_MISR(base)); + + /* Check for DM_RXSTALE for RX transfer to finish */ + while (!(status_reg & MSM_BOOT_UART_DM_RXSTALE)) { + status_reg = readl(MSM_BOOT_UART_DM_MISR(base)); + if (!wait) + return MSM_BOOT_UART_DM_E_RX_NOT_READY; + } + + /* Check for Overrun error. We'll just reset Error Status */ + if (readl(MSM_BOOT_UART_DM_SR(base)) & + MSM_BOOT_UART_DM_SR_UART_OVERRUN) { + writel(MSM_BOOT_UART_DM_CMD_RESET_ERR_STAT, + MSM_BOOT_UART_DM_CR(base)); + total_rx_data = rx_data_read = 0; + msm_boot_uart_dm_init(base); + return MSM_BOOT_UART_DM_E_RX_NOT_READY; + } + + /* Read UART_DM_RX_TOTAL_SNAP for actual number of bytes received */ + if (total_rx_data == 0) + total_rx_data = readl(MSM_BOOT_UART_DM_RX_TOTAL_SNAP(base)); + + /* Data available in FIFO; read a word. */ + *data = readl(MSM_BOOT_UART_DM_RF(base, 0)); + + /* WAR for http://prism/CR/548280 */ + if (*data == 0) + return MSM_BOOT_UART_DM_E_RX_NOT_READY; + + /* increment the total count of chars we've read so far */ + rx_data_read += FIFO_DATA_SIZE; + + /* actual count of valid data in word */ + *count = ((total_rx_data < rx_data_read) ? + (FIFO_DATA_SIZE - (rx_data_read - total_rx_data)) : + FIFO_DATA_SIZE); + + /* If there are still data left in FIFO we'll read them before + * initializing RX Transfer again + */ + if (rx_data_read < total_rx_data) + return MSM_BOOT_UART_DM_E_SUCCESS; + + msm_boot_uart_dm_init_rx_transfer(base); + total_rx_data = rx_data_read = 0; + + return MSM_BOOT_UART_DM_E_SUCCESS; +} +#endif + +void uart_tx_byte(int idx, unsigned char data) +{ + int num_of_chars = 1; + unsigned tx_data = 0; + void *base = uart_board_param.uart_dm_base; + + /* Wait until transmit FIFO is empty. */ + while (!(read32(MSM_BOOT_UART_DM_SR(base)) & + MSM_BOOT_UART_DM_SR_TXEMT)) + udelay(1); + /* + * TX FIFO is ready to accept new character(s). First write number of + * characters to be transmitted. + */ + write32(MSM_BOOT_UART_DM_NO_CHARS_FOR_TX(base), num_of_chars); + + /* And now write the character(s) */ + write32(MSM_BOOT_UART_DM_TF(base, 0), tx_data); +} +#endif /* CONFIG_SERIAL_UART */ + +/* + * msm_boot_uart_dm_reset - resets UART controller + * @base: UART controller base address + */ +static unsigned int msm_boot_uart_dm_reset(void *base) +{ + write32(MSM_BOOT_UART_DM_CR(base), MSM_BOOT_UART_DM_CMD_RESET_RX); + write32(MSM_BOOT_UART_DM_CR(base), MSM_BOOT_UART_DM_CMD_RESET_TX); + write32(MSM_BOOT_UART_DM_CR(base), + MSM_BOOT_UART_DM_CMD_RESET_ERR_STAT); + write32(MSM_BOOT_UART_DM_CR(base), MSM_BOOT_UART_DM_CMD_RES_TX_ERR); + write32(MSM_BOOT_UART_DM_CR(base), MSM_BOOT_UART_DM_CMD_RES_STALE_INT); + + return MSM_BOOT_UART_DM_E_SUCCESS; +} + +/* + * msm_boot_uart_dm_init - initilaizes UART controller + * @uart_dm_base: UART controller base address + */ +static unsigned int msm_boot_uart_dm_init(void *uart_dm_base) +{ + /* Configure UART mode registers MR1 and MR2 */ + /* Hardware flow control isn't supported */ + write32(MSM_BOOT_UART_DM_MR1(uart_dm_base), 0x0); + + /* 8-N-1 configuration: 8 data bits - No parity - 1 stop bit */ + write32(MSM_BOOT_UART_DM_MR2(uart_dm_base), + MSM_BOOT_UART_DM_8_N_1_MODE); + + /* Configure Interrupt Mask register IMR */ + write32(MSM_BOOT_UART_DM_IMR(uart_dm_base), + MSM_BOOT_UART_DM_IMR_ENABLED); + + /* + * Configure Tx and Rx watermarks configuration registers + * TX watermark value is set to 0 - interrupt is generated when + * FIFO level is less than or equal to 0 + */ + write32(MSM_BOOT_UART_DM_TFWR(uart_dm_base), + MSM_BOOT_UART_DM_TFW_VALUE); + + /* RX watermark value */ + write32(MSM_BOOT_UART_DM_RFWR(uart_dm_base), + MSM_BOOT_UART_DM_RFW_VALUE); + + /* Configure Interrupt Programming Register */ + /* Set initial Stale timeout value */ + write32(MSM_BOOT_UART_DM_IPR(uart_dm_base), + MSM_BOOT_UART_DM_STALE_TIMEOUT_LSB); + + /* Configure IRDA if required */ + /* Disabling IRDA mode */ + write32(MSM_BOOT_UART_DM_IRDA(uart_dm_base), 0x0); + + /* Configure hunt character value in HCR register */ + /* Keep it in reset state */ + write32(MSM_BOOT_UART_DM_HCR(uart_dm_base), 0x0); + + /* + * Configure Rx FIFO base address + * Both TX/RX shares same SRAM and default is half-n-half. + * Sticking with default value now. + * As such RAM size is (2^RAM_ADDR_WIDTH, 32-bit entries). + * We have found RAM_ADDR_WIDTH = 0x7f + */ + + /* Issue soft reset command */ + msm_boot_uart_dm_reset(uart_dm_base); + + /* Enable/Disable Rx/Tx DM interfaces */ + /* Data Mover not currently utilized. */ + write32(MSM_BOOT_UART_DM_DMEN(uart_dm_base), 0x0); + + /* Enable transmitter */ + write32(MSM_BOOT_UART_DM_CR(uart_dm_base), + MSM_BOOT_UART_DM_CR_TX_ENABLE); + + /* Initialize Receive Path */ + msm_boot_uart_dm_init_rx_transfer(uart_dm_base); + + return 0; +} + +/** + * ipq40xx_uart_init - initializes UART + * + * Initializes clocks, GPIO and UART controller. + */ +void uart_init(int idx) +{ + /* Note int idx isn't used in this driver. */ + void *dm_base; + void *gsbi_base; + + dm_base = uart_board_param.uart_dm_base; + + if (read32(MSM_BOOT_UART_DM_CSR(dm_base)) == UART_DM_CLK_RX_TX_BIT_RATE) + return; /* UART must have been already initialized. */ + + gsbi_base = uart_board_param.uart_gsbi_base; + ipq_configure_gpio(uart_board_param.dbg_uart_gpio, + NO_OF_DBG_UART_GPIOS); + + /* Configure the uart clock */ + uart_clock_config(uart_board_param.uart_gsbi, + uart_board_param.mnd_value.m_value, + uart_board_param.mnd_value.n_value, + uart_board_param.mnd_value.d_value, + 0); + + write32(GSBI_CTRL_REG(gsbi_base), + GSBI_PROTOCOL_CODE_I2C_UART << GSBI_CTRL_REG_PROTOCOL_CODE_S); + write32(MSM_BOOT_UART_DM_CSR(dm_base), UART_DM_CLK_RX_TX_BIT_RATE); + + /* Initialize UART_DM */ + msm_boot_uart_dm_init(dm_base); +} + +/* for the benefit of non-console uart init */ +void ipq40xx_uart_init(void) +{ + uart_init(0); +} + +#if 0 /* Not used yet */ +uint32_t uartmem_getbaseaddr(void) +{ + return (uint32_t)uart_board_param.uart_dm_base; +} +#endif + +/** + * uart_tx_flush - transmits a string of data + * @s: string to transmit + */ +void uart_tx_flush(int idx) +{ + void *base = uart_board_param.uart_dm_base; + + while (!(read32(MSM_BOOT_UART_DM_SR(base)) & + MSM_BOOT_UART_DM_SR_TXEMT)) + ; +} + +/** + * uart_can_rx_byte - checks if data available for reading + * + * Returns 1 if data available, 0 otherwise + */ + #if 0 /* Not used yet */ +int uart_can_rx_byte(void) +{ + /* Return if data is already read */ + if (valid_data) + return 1; + + /* Read data from the FIFO */ + if (msm_boot_uart_dm_read(&word, &valid_data, 0) != + MSM_BOOT_UART_DM_E_SUCCESS) + return 0; + + return 1; +} +#endif + +#if IS_ENABLED(CONFIG_DRIVERS_UART) +/** + * ipq40xx_serial_getc - reads a character + * + * Returns the character read from serial port. + */ +uint8_t uart_rx_byte(int idx) +{ + uint8_t byte; + +#if 0 /* Not used yet */ + while (!uart_can_rx_byte()) + ; /* wait for incoming data */ +#endif + byte = (uint8_t)(word & 0xff); + word = word >> 8; + valid_data--; + + return byte; +} +#endif + +#ifndef __PRE_RAM__ +/* TODO: Implement function */ +void uart_fill_lb(void *data) +{ +} +#endif diff --git a/src/soc/qualcomm/ipq40xx/usb.c b/src/soc/qualcomm/ipq40xx/usb.c new file mode 100644 index 0000000000..a8d991059f --- /dev/null +++ b/src/soc/qualcomm/ipq40xx/usb.c @@ -0,0 +1,222 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2014 Google Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * 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 <arch/io.h> +#include <console/console.h> +#include <delay.h> +#include <soc/clock.h> +#include <soc/iomap.h> +#include <soc/usb.h> + +#define CRPORT_TX_OVRD_DRV_LO 0x1002 +#define CRPORT_RX_OVRD_IN_HI 0x1006 +#define CRPORT_TX_ALT_BLOCK 0x102d + +static u32 * const tcsr_usb_sel = (void *)0x1a4000b0; + +struct usb_qc_phy { + u32 ipcat; + u32 ctrl; + u32 general_cfg; + u32 ram1; + u32 hs_phy_ctrl; + u32 param_ovrd; + u32 chrg_det_ctrl; + u32 chrg_det_output; + u32 alt_irq_en; + u32 hs_phy_irq_stat; + u32 cgctl; + u32 dbg_bus; + u32 ss_phy_ctrl; + u32 ss_phy_param1; + u32 ss_phy_param2; + u32 crport_data_in; + u32 crport_data_out; + u32 crport_cap_addr; + u32 crport_cap_data; + u32 crport_ack_read; + u32 crport_ack_write; +}; +check_member(usb_qc_phy, crport_ack_write, 0x50); + +static struct usb_qc_phy * const usb_host1_phy = (void *)USB_HOST1_PHY_BASE; +static struct usb_qc_phy * const usb_host2_phy = (void *)USB_HOST2_PHY_BASE; + +struct usb_dwc3 { + u32 sbuscfg0; + u32 sbuscfg1; + u32 txthrcfg; + u32 rxthrcfg; + u32 ctl; + u32 evten; + u32 sts; + u8 reserved0[4]; + u32 snpsid; + u32 gpio; + u32 uid; + u32 uctl; + u64 buserraddr; + u64 prtbimap; + u8 reserved1[32]; + u32 dbgfifospace; + u32 dbgltssm; + u32 dbglnmcc; + u32 dbgbmu; + u32 dbglspmux; + u32 dbglsp; + u32 dbgepinfo0; + u32 dbgepinfo1; + u64 prtbimap_hs; + u64 prtbimap_fs; + u8 reserved2[112]; + u32 usb2phycfg; + u8 reserved3[60]; + u32 usb2i2cctl; + u8 reserved4[60]; + u32 usb2phyacc; + u8 reserved5[60]; + u32 usb3pipectl; + u8 reserved6[60]; +}; +check_member(usb_dwc3, usb3pipectl, 0x1c0); + +static struct usb_dwc3 * const usb_host1_dwc3 = (void *)USB_HOST1_DWC3_BASE; +static struct usb_dwc3 * const usb_host2_dwc3 = (void *)USB_HOST2_DWC3_BASE; + +static void setup_dwc3(struct usb_dwc3 *dwc3) +{ + write32(&dwc3->usb3pipectl, + 0x1 << 31 | /* assert PHY soft reset */ + 0x1 << 25 | /* (default) U1/U2 exit fail -> recovery? */ + 0x1 << 24 | /* (default) activate PHY low power states */ + 0x1 << 19 | /* (default) PHY low power delay value */ + 0x1 << 18 | /* (default) activate PHY low power delay */ + 0x1 << 1 | /* (default) Tx deemphasis value */ + 0x1 << 0); /* (default) elastic buffer mode */ + + write32(&dwc3->usb2phycfg, + 0x1 << 31 | /* assert PHY soft reset */ + 0x9 << 10 | /* (default) PHY clock turnaround 8-bit UTMI+ */ + 0x1 << 8 | /* (default) enable PHY sleep in L1 */ + 0x1 << 6); /* (default) enable PHY suspend */ + + write32(&dwc3->ctl, + 0x2 << 19 | /* (default) suspend clock scaling */ + 0x1 << 16 | /* retry SS three times before HS downgrade */ + 0x1 << 12 | /* port capability HOST */ + 0x1 << 11 | /* assert core soft reset */ + 0x1 << 10 | /* (default) sync ITP to refclk */ + 0x1 << 2); /* U2 exit after 8us LFPS (instead of 248ns) */ + + write32(&dwc3->uctl, + 0x32 << 22 | /* (default) reference clock period in ns */ + 0x1 << 15 | /* (default) XHCI compliant device addressing */ + 0x10 << 0); /* (default) devices time out after 32us */ + + udelay(5); + + clrbits_le32(&dwc3->ctl, 0x1 << 11); /* deassert core soft reset */ + clrbits_le32(&dwc3->usb2phycfg, 0x1 << 31); /* PHY soft reset */ + clrbits_le32(&dwc3->usb3pipectl, 0x1 << 31); /* PHY soft reset */ +} + +static void setup_phy(struct usb_qc_phy *phy) +{ + write32(&phy->ss_phy_ctrl, + 0x1 << 24 | /* Indicate VBUS power present */ + 0x1 << 8 | /* Enable USB3 ref clock to prescaler */ + 0x1 << 7 | /* assert SS PHY reset */ + 0x19 << 0); /* (default) reference clock multiplier */ + + write32(&phy->hs_phy_ctrl, + 0x1 << 26 | /* (default) unclamp DPSE/DMSE VLS */ + 0x1 << 25 | /* (default) select freeclk for utmi_clk */ + 0x1 << 24 | /* (default) unclamp DMSE VLS */ + 0x1 << 21 | /* (default) enable UTMI clock */ + 0x1 << 20 | /* set OTG VBUS as valid */ + 0x1 << 18 | /* use ref clock from core */ + 0x1 << 17 | /* (default) unclamp DPSE VLS */ + 0x1 << 11 | /* force xo/bias/pll to stay on in suspend */ + 0x1 << 9 | /* (default) unclamp IDHV */ + 0x1 << 8 | /* (default) unclamp VLS (again???) */ + 0x1 << 7 | /* (default) unclamp HV VLS */ + 0x7 << 4 | /* select frequency (no idea which one) */ + 0x1 << 1); /* (default) "retention enable" */ + + write32(&phy->ss_phy_param1, + 0x6e << 20 | /* full TX swing amplitude */ + 0x20 << 14 | /* (default) 6dB TX deemphasis */ + 0x17 << 8 | /* 3.5dB TX deemphasis */ + 0x9 << 3); /* (default) LoS detector level */ + + write32(&phy->general_cfg, 0x1 << 2); /* set XHCI 1.00 compliance */ + + udelay(5); + clrbits_le32(&phy->ss_phy_ctrl, 0x1 << 7); /* deassert SS PHY reset */ +} + +static void crport_handshake(void *capture_reg, void *acknowledge_bit, u32 data) +{ + int usec = 100; + + if (capture_reg) + write32(capture_reg, data); + + write32(acknowledge_bit, 0x1 << 0); + while (read32(acknowledge_bit) && --usec) + udelay(1); + + if (!usec) + printk(BIOS_ERR, "CRPORT handshake timed out (0x%08x)\n", data); +} + +static void crport_write(struct usb_qc_phy *phy, u16 addr, u16 data) +{ + crport_handshake(&phy->crport_data_in, &phy->crport_cap_addr, addr); + crport_handshake(&phy->crport_data_in, &phy->crport_cap_data, data); + crport_handshake(NULL, &phy->crport_ack_write, 0); +} + +static void tune_phy(struct usb_qc_phy *phy) +{ + crport_write(phy, CRPORT_RX_OVRD_IN_HI, + 0x1 << 11 | /* Set RX_EQ override? */ + 0x4 << 8 | /* Set RX_EQ to 4? */ + 0x1 << 7); /* Enable RX_EQ override */ + crport_write(phy, CRPORT_TX_OVRD_DRV_LO, + 0x1 << 14 | /* Enable amplitude (override?) */ + 0x17 << 7 | /* Set TX deemphasis to 23 */ + 0x6e << 0); /* Set amplitude to 110 */ + crport_write(phy, CRPORT_TX_ALT_BLOCK, + 0x1 << 7); /* ALT block? ("partial RX reset") */ +} + +void setup_usb_host1(void) +{ + printk(BIOS_INFO, "Setting up USB HOST1 controller...\n"); + setbits_le32(tcsr_usb_sel, 1 << 0); /* Select DWC3 controller */ + setup_phy(usb_host1_phy); + setup_dwc3(usb_host1_dwc3); + tune_phy(usb_host1_phy); +} + +void setup_usb_host2(void) +{ + printk(BIOS_INFO, "Setting up USB HOST2 controller...\n"); + setbits_le32(tcsr_usb_sel, 1 << 1); /* Select DWC3 controller */ + setup_phy(usb_host2_phy); + setup_dwc3(usb_host2_dwc3); + tune_phy(usb_host2_phy); +} |