blob: 3ffa30da032593f77427a88c818c00af0201c4cf [file] [log] [blame]
/*
* Copyright (c) 2015 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/*
* This file was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
#ifndef __HIF_IO32_PCI_H__
#define __HIF_IO32_PCI_H__
#ifdef HIF_PCI
#include "hif.h"
#include "regtable.h"
#include "ce_reg.h"
#include "cdf_atomic.h"
#include "if_pci.h"
/*
* For maximum performance and no power management, set this to 1.
* For power management at the cost of performance, set this to 0.
*/
#define CONFIG_ATH_PCIE_MAX_PERF 0
/*
* For keeping the target awake till the driver is
* loaded, set this to 1
*/
#define CONFIG_ATH_PCIE_AWAKE_WHILE_DRIVER_LOAD 1
/*
* When CONFIG_ATH_PCIE_MAX_PERF is 0:
* To use LIKELY hints, set this to 1 (slightly better performance, more power)
* To ignore "LIKELY" hints, set this to 0 (slightly worse performance,
* less power)
*/
#if defined(CONFIG_ATH_PCIE_MAX_PERF)
#define CONFIG_ATH_PCIE_ACCESS_LIKELY 0
#else
#define CONFIG_ATH_PCIE_ACCESS_LIKELY 1
#endif
/*
* PCI-E L1 ASPPM sub-states
* To enable clock gating in L1 state, set this to 1.
* (less power, slightly more wakeup latency)
* To disable clock gating in L1 state, set this to 0. (slighly more power)
*/
#define CONFIG_PCIE_ENABLE_L1_CLOCK_GATE 1
/*
* PCIE_ACCESS_LOG_NUM specifies the number of
* read/write records to store
*/
#ifdef CONFIG_ATH_PCIE_ACCESS_DEBUG
#define PCIE_ACCESS_LOG_NUM 500
#endif
/* 64-bit MSI support */
#define CONFIG_PCIE_64BIT_MSI 0
/* BAR0 ready checking for AR6320v2 */
#define PCIE_BAR0_READY_CHECKING 0
/* AXI gating when L1, L2 to reduce power consumption */
#define CONFIG_PCIE_ENABLE_AXI_CLK_GATE 0
#define hif_read32_mb(addr) ioread32((void __iomem *)addr)
#define hif_write32_mb(addr, value) \
iowrite32((u32)(value), (void __iomem *)(addr))
extern int hif_target_sleep_state_adjust(struct ol_softc *scn,
bool sleep_ok,
bool wait_for_it);
#if CONFIG_ATH_PCIE_MAX_PERF
#define A_TARGET_ACCESS_BEGIN(scn) \
do {struct ol_softc *unused = scn; \
unused = unused; } while (0)
#define A_TARGET_ACCESS_END(scn) \
do {struct ol_softc *unused = scn; \
unused = unused; } while (0)
#define A_TARGET_ACCESS_OK(scn) 1
#define A_TARGET_ACCESS_LIKELY(scn) \
do {struct ol_softc *unused = scn; \
unused = unused; } while (0)
#define A_TARGET_ACCESS_UNLIKELY(scn) \
do {struct ol_softc *unused = scn; \
unused = unused; } while (0)
#define A_TARGET_READ(scn, offset) \
hif_read32_mb(scn->mem + (offset))
void war_pci_write32(char *addr, u32 offset, u32 value);
#define A_TARGET_WRITE(scn, offset, value) \
war_pci_write32(scn->mem, (offset), (value))
#define A_TARGET_ACCESS_BEGIN_RET(scn) \
do {struct ol_softc *unused = scn; \
unused = unused; } while (0)
#define A_TARGET_ACCESS_BEGIN_RET_EXT(scn, val) \
do {struct ol_softc *unused = scn; \
unused = unused; } while (0)
#define A_TARGET_ACCESS_BEGIN_RET_PTR(scn) \
do {struct ol_softc *unused = scn; \
unused = unused; } while (0)
#define A_TARGET_ACCESS_END_RET(scn) \
do {struct ol_softc *unused = scn; \
unused = unused; } while (0)
#define A_TARGET_ACCESS_END_RET_EXT(scn, val) \
do {struct ol_softc *unused = scn; \
unused = unused; } while (0)
#define A_TARGET_ACCESS_END_RET_PTR(scn) \
do {struct ol_softc *unused = scn; \
unused = unused; } while (0)
#else /* CONFIG_ATH_PCIE_MAX_PERF */
void war_pci_write32(char *addr, u32 offset, u32 value);
#define A_TARGET_ACCESS_BEGIN_RET_EXT(scn, val) \
do { \
if (!WLAN_IS_EPPING_ENABLED(cds_get_conparam()) && \
Q_TARGET_ACCESS_BEGIN(scn) < 0) \
val = -1; \
} while (0)
#define A_TARGET_ACCESS_BEGIN_RET(scn) \
do { \
if (!WLAN_IS_EPPING_ENABLED(cds_get_conparam()) && \
Q_TARGET_ACCESS_BEGIN(scn) < 0) \
return ATH_ISR_NOSCHED; \
} while (0)
#define A_TARGET_ACCESS_BEGIN_RET_PTR(scn) \
do { \
if (!WLAN_IS_EPPING_ENABLED(cds_get_conparam()) && \
Q_TARGET_ACCESS_BEGIN(scn) < 0) \
return NULL; \
} while (0)
#define A_TARGET_ACCESS_BEGIN(scn) \
do { \
if (Q_TARGET_ACCESS_BEGIN(scn) < 0) \
return; \
} while (0)
#define Q_TARGET_ACCESS_BEGIN(scn) \
hif_target_sleep_state_adjust(scn, false, true)
#define A_TARGET_ACCESS_END_RET(scn) \
do { \
if (!WLAN_IS_EPPING_ENABLED(cds_get_conparam()) && \
Q_TARGET_ACCESS_END(scn) < 0) \
return ATH_ISR_NOSCHED; \
} while (0)
#define A_TARGET_ACCESS_END_RET_EXT(scn, val) \
do { \
if (!WLAN_IS_EPPING_ENABLED(cds_get_conparam()) && \
Q_TARGET_ACCESS_END(scn) < 0) \
val = -1; \
} while (0)
#define A_TARGET_ACCESS_END_RET_PTR(scn) \
do { \
if (!WLAN_IS_EPPING_ENABLED(cds_get_conparam()) && \
Q_TARGET_ACCESS_END(scn) < 0) \
return NULL; \
} while (0)
#define A_TARGET_ACCESS_END(scn) \
do { \
if (Q_TARGET_ACCESS_END(scn) < 0) \
return; \
} while (0)
#define Q_TARGET_ACCESS_END(scn) \
hif_target_sleep_state_adjust(scn, true, false)
#define A_TARGET_ACCESS_OK(scn) hif_target_forced_awake(scn)
#if CONFIG_ATH_PCIE_ACCESS_LIKELY
#define A_TARGET_ACCESS_LIKELY(scn) \
hif_target_sleep_state_adjust(scn, false, false)
#define A_TARGET_ACCESS_UNLIKELY(scn) \
hif_target_sleep_state_adjust(scn, true, false)
#else /* CONFIG_ATH_PCIE_ACCESS_LIKELY */
#define A_TARGET_ACCESS_LIKELY(scn) \
do { \
unsigned long unused = (unsigned long)(scn); \
unused = unused; \
} while (0)
#define A_TARGET_ACCESS_UNLIKELY(scn) \
do { \
unsigned long unused = (unsigned long)(scn); \
unused = unused; \
} while (0)
#endif /* CONFIG_ATH_PCIE_ACCESS_LIKELY */
#ifdef CONFIG_ATH_PCIE_ACCESS_DEBUG
extern uint32_t hif_target_read_checked(struct ol_softc *scn,
uint32_t offset);
extern void hif_target_write_checked(struct ol_softc *scn, uint32_t offset,
uint32_t value);
#define A_TARGET_READ(scn, offset) \
hif_target_read_checked(scn, (offset))
#define A_TARGET_WRITE(scn, offset, value) \
hif_target_write_checked(scn, (offset), (value))
#else /* CONFIG_ATH_PCIE_ACCESS_DEBUG */
#define A_TARGET_READ(scn, offset) \
hif_read32_mb(scn->mem + (offset))
#define A_TARGET_WRITE(scn, offset, value) \
war_pci_write32(scn->mem, (offset), (value))
#endif
#endif /* CONFIG_ATH_PCIE_MAX_PERF */
/**
* ce_irq_enable() - ce_irq_enable
* @scn: ol_softc
* @ce_id: ce_id
*
* Return: void
*/
static inline void ce_irq_enable(struct ol_softc *scn, int ce_id)
{
uint32_t tmp = 1 << ce_id;
struct hif_pci_softc *sc = scn->hif_sc;
cdf_spin_lock_irqsave(&scn->irq_lock);
scn->ce_irq_summary &= ~tmp;
if (scn->ce_irq_summary == 0) {
/* Enable Legacy PCI line interrupts */
if (LEGACY_INTERRUPTS(sc) &&
(scn->target_status != OL_TRGET_STATUS_RESET) &&
(!cdf_atomic_read(&scn->link_suspended))) {
hif_write32_mb(scn->mem +
(SOC_CORE_BASE_ADDRESS |
PCIE_INTR_ENABLE_ADDRESS),
HOST_GROUP0_MASK);
hif_read32_mb(scn->mem +
(SOC_CORE_BASE_ADDRESS |
PCIE_INTR_ENABLE_ADDRESS));
}
}
if (scn->hif_init_done == true)
A_TARGET_ACCESS_END(scn);
cdf_spin_unlock_irqrestore(&scn->irq_lock);
}
/**
* ce_irq_disable() - ce_irq_disable
* @scn: ol_softc
* @ce_id: ce_id
*
* Return: void
*/
static inline void ce_irq_disable(struct ol_softc *scn, int ce_id)
{
/* For Rome only need to wake up target */
A_TARGET_ACCESS_BEGIN(scn);
}
/**
* soc_wake_reset() - soc_wake_reset
* @scn: ol_softc
*
* Return: void
*/
static inline void soc_wake_reset(struct ol_softc *scn)
{
hif_write32_mb(scn->mem +
PCIE_LOCAL_BASE_ADDRESS +
PCIE_SOC_WAKE_ADDRESS,
PCIE_SOC_WAKE_RESET);
}
#endif /* HIF_PCI */
#endif /* __HIF_IO32_PCI_H__ */