blob: 1ecfc3c80aaaadd1812bc6e96d9694caec413619 [file] [log] [blame]
/**
Copyright (c) 2008 - 2013 Quantenna Communications Inc
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; either version 2
of the License, or (at your option) any later version.
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.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
#ifndef AUTOCONF_INCLUDED
#include <linux/config.h>
#endif
#include <linux/version.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <asm/hardware.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0)
#include <linux/gpio.h>
#else
#include <asm/gpio.h>
#endif
#include "qdrv_features.h"
#include "qdrv_debug.h"
#include "qdrv_hal.h"
#include "qdrv_mac.h"
#include "qdrv_soc.h"
#include <qtn/registers.h>
#include <qtn/shared_params.h>
#include <qtn/txbf_mbox.h>
#include <qtn/qtn_bb_mutex.h>
#include <common/topaz_reset.h>
/* unaligned little endian access */
#define LE_READ_4(p) ((u_int32_t) \
((((const u_int8_t *)(p))[0]) | \
(((const u_int8_t *)(p))[1] << 8) | \
(((const u_int8_t *)(p))[2] << 16) | \
(((const u_int8_t *)(p))[3] << 24)))
void hal_get_tsf(uint64_t *ret)
{
uint64_t tsf64;
uint32_t *tsf = (uint32_t *) &tsf64;
uint32_t temp_tsf1;
qtn_bb_mutex_enter(QTN_LHOST_SOC_CPU);
temp_tsf1 = readl(HAL_REG(HAL_REG_TSF_HI));
tsf[0] = readl(HAL_REG(HAL_REG_TSF_LO));
tsf[1] = readl(HAL_REG(HAL_REG_TSF_HI));
if (temp_tsf1 != tsf[1]) /* handling wrap-around case. */
tsf[0] = readl(HAL_REG(HAL_REG_TSF_LO));
qtn_bb_mutex_leave(QTN_LHOST_SOC_CPU);
*ret = tsf64;
}
void hal_reset(void)
{
u32 reset;
#ifdef CONFIG_ARC
reset = RUBY_SYS_CTL_RESET_NETSS | RUBY_SYS_CTL_RESET_MAC | RUBY_SYS_CTL_RESET_BB;
/* Reset MAC HW */
writel(reset, SYS_RESET_VECTOR_MASK);
writel(reset, SYS_RESET_VECTOR);
udelay(50);
writel(0, SYS_RESET_VECTOR_MASK);
/*
* After MAC reset the Rx path is enabled, disabling it here.
* Note: This may need to be revisited for Mu-MIMO, or QAC3.
*/
writel(0, HAL_REG(HAL_REG_RX_CSR));
# if !TOPAZ_FPGA_PLATFORM
/*
* Special programming to turn off the power amplifiers
* immediately after bringing the baseband out of reset.
*
* Baseband has to be put into Soft Reset for this operation to work.
*/
writel(0x04, QT3_BB_GLBL_SOFT_RST);
writel(0x0bb5, QT3_BB_TD_PA_CONF);
writel(0x00, QT3_BB_GLBL_SOFT_RST);
/*
* Bring the RFIC out of reset by first driving GPIO 15 (RFIC RESET) to be low
* for 10 usec, and then driving it high.
*/
if (gpio_request(RUBY_GPIO_RFIC_RESET, "rfic_reset") < 0)
printk(KERN_ERR "Failed to request GPIO%d for GPIO rfic_reset\n",
RUBY_GPIO_RFIC_RESET);
gpio_direction_output(RUBY_GPIO_RFIC_RESET, 0);
udelay(10);
gpio_set_value(RUBY_GPIO_RFIC_RESET, 1);
gpio_free(RUBY_GPIO_RFIC_RESET);
# endif /* !TOPAZ_FPGA_PLATFORM */
#else
/* BBIC2 - non-ARC processor */
reset = DSPSS_RESET | NETSS_RESET | MMC_RESET | BB_RESET | MB_RESET | SRAM_RESET | BB_RESET;
/* Reset MAC HW */
writel(reset, SYS_RESET_VECTOR_MASK);
writel(reset, SYS_RESET_VECTOR);
udelay(50);
/* fix soft-reset polarity issue BBIC2 */
writel(0x2030, BB_PREG_SPARE_0(0));
#endif /* CONFIG_ARC */
}
void hal_enable_muc(u32 muc_start_addr)
{
const unsigned long reset = RUBY_SYS_CTL_RESET_MUC_ALL;
#ifdef FIXME_NOW
volatile u32 value;
#endif
#ifdef CONFIG_ARC
/* Check that we can start this address */
if (muc_start_addr & ((1 << RUBY_SYS_CTL_MUC_REMAP_SHIFT) - 1)) {
panic("MuC address 0x%x cannot be used as entry point\n", (unsigned)muc_start_addr);
}
/* Tells MuC its boot address */
writel(RUBY_SYS_CTL_MUC_REMAP_VAL(muc_start_addr), RUBY_SYS_CTL_MUC_REMAP);
/* Take MUC out of reset */
topaz_set_reset_vec(1, reset);
DBGPRINTF(DBG_LL_INFO, QDRV_LF_TRACE, "Reset MuC and enabled MuC boot remap %08X\n", readl(RUBY_SYS_CTL_MUC_REMAP));
#else
/* Take MUC out of reset */
*(volatile u32 *)IO_ADDRESS(SYS_RESET_VECTOR_MASK) = MUC_RESET;
*(volatile u32 *)IO_ADDRESS(SYS_RESET_VECTOR) = MUC_RESET;
#endif //CONFIG_ARC
#ifdef FIXME_NOW
/* Set bit 15 for DGPIO enable */
value = *(volatile u32 *)IO_ADDRESS(SYS_CONTROL_MASK);
*(volatile u32 *)IO_ADDRESS(SYS_CONTROL_MASK) = value | DSP_MASTER_GPIO_ENABLE;
value = *(volatile u32 *) IO_ADDRESS(SYS_CONTROL_REG);
*(volatile u32 *)IO_ADDRESS(SYS_CONTROL_REG) = value | DSP_MASTER_GPIO_ENABLE;
#endif
}
void hal_disable_muc(void)
{
#ifdef CONFIG_ARC
topaz_set_reset_vec(0, RUBY_SYS_CTL_RESET_MUC_ALL);
#else
*(volatile u32 *)IO_ADDRESS(SYS_RESET_VECTOR_MASK) = MUC_RESET;
*(volatile u32 *)IO_ADDRESS(SYS_RESET_VECTOR) = 0;
#endif
}
EXPORT_SYMBOL(hal_disable_muc);
void hal_enable_mbx(void)
{
*(volatile u32 *)IO_ADDRESS(SYS_RESET_VECTOR_MASK) = MB_RESET;
*(volatile u32 *)IO_ADDRESS(SYS_RESET_VECTOR) = MB_RESET;
}
void hal_disable_mbx(void)
{
/* Clear the mailboxes by cycling them */
*(volatile u32 *)IO_ADDRESS(SYS_RESET_VECTOR_MASK) = MB_RESET;
*(volatile u32 *)IO_ADDRESS(SYS_RESET_VECTOR) = 0;
}
void hal_disable_dsp(void)
{
#ifdef CONFIG_ARC
# if 0
# error writing to this hangs the bus
const unsigned long reset = RUBY_SYS_CTL_RESET_DSP_ALL;
topaz_set_reset_vec(0, reset);
# endif
#else
/* Hold the DSP in reset */
*(volatile u32 *)IO_ADDRESS(SYS_RESET_VECTOR_MASK) = DSP_RESET;
*(volatile u32 *)IO_ADDRESS(SYS_RESET_VECTOR) = 0;
#endif
}
void hal_enable_dsp(void)
{
#ifdef CONFIG_ARC
const unsigned long reset = RUBY_SYS_CTL_RESET_DSP_ALL;
qtn_txbf_lhost_init();
topaz_set_reset_vec(1, reset);
#else
/* Bring the DSP out of reset */
*(volatile u32 *)IO_ADDRESS(SYS_RESET_VECTOR_MASK) = DSP_RESET;
*(volatile u32 *)IO_ADDRESS(SYS_RESET_VECTOR) = DSP_RESET;
#endif
}
void hal_enable_gpio(void)
{
u32 value;
/* Set bit 15 for DGPIO enable */
value = *(volatile u32 *)IO_ADDRESS(SYS_CONTROL_MASK);
*(volatile u32 *)IO_ADDRESS(SYS_CONTROL_MASK) =
value | DSP_MASTER_GPIO_ENABLE;
value = *(volatile u32 *)IO_ADDRESS(SYS_CONTROL_REG);
*(volatile u32 *)IO_ADDRESS(SYS_CONTROL_REG) =
value | DSP_MASTER_GPIO_ENABLE;
}
#define DSP_JUMP_INSTR_SWAP 0x0F802020
void hal_dsp_start(u32 dsp_start_addr)
{
#ifdef CONFIG_ARC
/* Check that we can start this address */
if (dsp_start_addr & ((1 << RUBY_SYS_CTL_DSP_REMAP_SHIFT) - 1)) {
panic("DSP address 0x%x cannot be used as entry point\n", (unsigned)dsp_start_addr);
}
/* Tells DSP from which address start execution */
writel(RUBY_SYS_CTL_DSP_REMAP_VAL(dsp_start_addr), RUBY_SYS_CTL_DSP_REMAP);
#else
/* Swap upper and lower half words for DSP instruction */
dsp_start_addr = ((dsp_start_addr >> 16) & 0xFFFF) | (dsp_start_addr << 16);
/* Push the jump instr and location into the mbx */
*(volatile u32*)IO_ADDRESS(UMS_REGS_MB + UMS_MBX_DSP_PUSH)
= DSP_JUMP_INSTR_SWAP;
*(volatile u32*)IO_ADDRESS(UMS_REGS_MB + UMS_MBX_DSP_PUSH)
= dsp_start_addr;
#endif
}
void hal_disable_auc(void)
{
}
void hal_enable_auc(void)
{
const unsigned long reset = TOPAZ_SYS_CTL_RESET_AUC;
topaz_set_reset_vec(1, reset);
}
int hal_range_check_sram_addr(void *addr)
{
/*
* FIXME!!!
*
* On Ruby platform MuC firmware can use several sections mapped to different
* (not joined) address ranges. So there are no simple way to detect whether address
* is valid or not (check should determine whether address belongs to any of these
* sections or not).
* And for sure this function should not have "sram" in its name.
* For Ruby not only SRAM is used for MuC!
* For now let's always return success.
*/
return(0);
}
void hal_rf_enable()
{
volatile u32 *addr;
/* set bit 15 for DGPIO enable */
addr = (volatile u32 *)IO_ADDRESS(SYS_CONTROL_MASK);
*addr |= DSP_MASTER_GPIO_ENABLE;
addr = (volatile u32 *)IO_ADDRESS(SYS_CONTROL_REG);
*addr |= DSP_MASTER_GPIO_ENABLE;
addr = (volatile u32 *)IO_ADDRESS(RUBY_GPIO_REGS_ADDR + GPIO_MODE1);
*addr |= GPIO_MODE_OUTPUT << (15 << 1);
addr = (volatile u32 *)IO_ADDRESS(RUBY_GPIO_REGS_ADDR + GPIO_MODE2);
*addr |= (GPIO_MODE_OUTPUT << (9 << 1)) | (GPIO_MODE_OUTPUT << (13 << 1));
addr = (volatile u32 *)IO_ADDRESS(RUBY_GPIO_REGS_ADDR + GPIO_OUTPUT_MASK);
*addr |= (1 << 15) | (1 << 25);
addr = (volatile u32 *)IO_ADDRESS(RUBY_GPIO_REGS_ADDR + GPIO_OUTPUT);
*addr |= (1 << 15) | (1 << 25);
addr = (volatile u32 *)IO_ADDRESS(RUBY_GPIO_REGS_ADDR + GPIO_ALTFN);
*addr |= (1 << 29);
}