wifi: brcmfmac: pcie: Support PCIe core revisions >= 64

These newer PCIe core revisions include new sets of registers that must
be used instead of the legacy ones. Introduce a brcmf_pcie_reginfo to
hold the specific register offsets and values to use for a given
platform, and change all the register accesses to indirect through it.

Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Hector Martin <marcan@marcan.st>
Signed-off-by: Kalle Valo <kvalo@kernel.org>
Link: https://lore.kernel.org/r/E1oZDo8-0077aq-6I@rmk-PC.armlinux.org.uk
This commit is contained in:
Hector Martin 2022-09-16 17:03:12 +01:00 committed by Kalle Valo
parent f48476780c
commit e01d7a5469
1 changed files with 105 additions and 20 deletions

View File

@ -119,6 +119,12 @@ static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = {
#define BRCMF_PCIE_PCIE2REG_H2D_MAILBOX_0 0x140
#define BRCMF_PCIE_PCIE2REG_H2D_MAILBOX_1 0x144
#define BRCMF_PCIE_64_PCIE2REG_INTMASK 0xC14
#define BRCMF_PCIE_64_PCIE2REG_MAILBOXINT 0xC30
#define BRCMF_PCIE_64_PCIE2REG_MAILBOXMASK 0xC34
#define BRCMF_PCIE_64_PCIE2REG_H2D_MAILBOX_0 0xA20
#define BRCMF_PCIE_64_PCIE2REG_H2D_MAILBOX_1 0xA24
#define BRCMF_PCIE2_INTA 0x01
#define BRCMF_PCIE2_INTB 0x02
@ -138,6 +144,8 @@ static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = {
#define BRCMF_PCIE_MB_INT_D2H3_DB0 0x400000
#define BRCMF_PCIE_MB_INT_D2H3_DB1 0x800000
#define BRCMF_PCIE_MB_INT_FN0 (BRCMF_PCIE_MB_INT_FN0_0 | \
BRCMF_PCIE_MB_INT_FN0_1)
#define BRCMF_PCIE_MB_INT_D2H_DB (BRCMF_PCIE_MB_INT_D2H0_DB0 | \
BRCMF_PCIE_MB_INT_D2H0_DB1 | \
BRCMF_PCIE_MB_INT_D2H1_DB0 | \
@ -147,6 +155,40 @@ static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = {
BRCMF_PCIE_MB_INT_D2H3_DB0 | \
BRCMF_PCIE_MB_INT_D2H3_DB1)
#define BRCMF_PCIE_64_MB_INT_D2H0_DB0 0x1
#define BRCMF_PCIE_64_MB_INT_D2H0_DB1 0x2
#define BRCMF_PCIE_64_MB_INT_D2H1_DB0 0x4
#define BRCMF_PCIE_64_MB_INT_D2H1_DB1 0x8
#define BRCMF_PCIE_64_MB_INT_D2H2_DB0 0x10
#define BRCMF_PCIE_64_MB_INT_D2H2_DB1 0x20
#define BRCMF_PCIE_64_MB_INT_D2H3_DB0 0x40
#define BRCMF_PCIE_64_MB_INT_D2H3_DB1 0x80
#define BRCMF_PCIE_64_MB_INT_D2H4_DB0 0x100
#define BRCMF_PCIE_64_MB_INT_D2H4_DB1 0x200
#define BRCMF_PCIE_64_MB_INT_D2H5_DB0 0x400
#define BRCMF_PCIE_64_MB_INT_D2H5_DB1 0x800
#define BRCMF_PCIE_64_MB_INT_D2H6_DB0 0x1000
#define BRCMF_PCIE_64_MB_INT_D2H6_DB1 0x2000
#define BRCMF_PCIE_64_MB_INT_D2H7_DB0 0x4000
#define BRCMF_PCIE_64_MB_INT_D2H7_DB1 0x8000
#define BRCMF_PCIE_64_MB_INT_D2H_DB (BRCMF_PCIE_64_MB_INT_D2H0_DB0 | \
BRCMF_PCIE_64_MB_INT_D2H0_DB1 | \
BRCMF_PCIE_64_MB_INT_D2H1_DB0 | \
BRCMF_PCIE_64_MB_INT_D2H1_DB1 | \
BRCMF_PCIE_64_MB_INT_D2H2_DB0 | \
BRCMF_PCIE_64_MB_INT_D2H2_DB1 | \
BRCMF_PCIE_64_MB_INT_D2H3_DB0 | \
BRCMF_PCIE_64_MB_INT_D2H3_DB1 | \
BRCMF_PCIE_64_MB_INT_D2H4_DB0 | \
BRCMF_PCIE_64_MB_INT_D2H4_DB1 | \
BRCMF_PCIE_64_MB_INT_D2H5_DB0 | \
BRCMF_PCIE_64_MB_INT_D2H5_DB1 | \
BRCMF_PCIE_64_MB_INT_D2H6_DB0 | \
BRCMF_PCIE_64_MB_INT_D2H6_DB1 | \
BRCMF_PCIE_64_MB_INT_D2H7_DB0 | \
BRCMF_PCIE_64_MB_INT_D2H7_DB1)
#define BRCMF_PCIE_SHARED_VERSION_7 7
#define BRCMF_PCIE_MIN_SHARED_VERSION 5
#define BRCMF_PCIE_MAX_SHARED_VERSION BRCMF_PCIE_SHARED_VERSION_7
@ -273,6 +315,7 @@ struct brcmf_pciedev_info {
char nvram_name[BRCMF_FW_NAME_LEN];
char clm_name[BRCMF_FW_NAME_LEN];
const struct firmware *clm_fw;
const struct brcmf_pcie_reginfo *reginfo;
void __iomem *regs;
void __iomem *tcm;
u32 ram_base;
@ -359,6 +402,36 @@ static const u32 brcmf_ring_itemsize[BRCMF_NROF_COMMON_MSGRINGS] = {
BRCMF_D2H_MSGRING_RX_COMPLETE_ITEMSIZE
};
struct brcmf_pcie_reginfo {
u32 intmask;
u32 mailboxint;
u32 mailboxmask;
u32 h2d_mailbox_0;
u32 h2d_mailbox_1;
u32 int_d2h_db;
u32 int_fn0;
};
static const struct brcmf_pcie_reginfo brcmf_reginfo_default = {
.intmask = BRCMF_PCIE_PCIE2REG_INTMASK,
.mailboxint = BRCMF_PCIE_PCIE2REG_MAILBOXINT,
.mailboxmask = BRCMF_PCIE_PCIE2REG_MAILBOXMASK,
.h2d_mailbox_0 = BRCMF_PCIE_PCIE2REG_H2D_MAILBOX_0,
.h2d_mailbox_1 = BRCMF_PCIE_PCIE2REG_H2D_MAILBOX_1,
.int_d2h_db = BRCMF_PCIE_MB_INT_D2H_DB,
.int_fn0 = BRCMF_PCIE_MB_INT_FN0,
};
static const struct brcmf_pcie_reginfo brcmf_reginfo_64 = {
.intmask = BRCMF_PCIE_64_PCIE2REG_INTMASK,
.mailboxint = BRCMF_PCIE_64_PCIE2REG_MAILBOXINT,
.mailboxmask = BRCMF_PCIE_64_PCIE2REG_MAILBOXMASK,
.h2d_mailbox_0 = BRCMF_PCIE_64_PCIE2REG_H2D_MAILBOX_0,
.h2d_mailbox_1 = BRCMF_PCIE_64_PCIE2REG_H2D_MAILBOX_1,
.int_d2h_db = BRCMF_PCIE_64_MB_INT_D2H_DB,
.int_fn0 = 0,
};
static void brcmf_pcie_setup(struct device *dev, int ret,
struct brcmf_fw_request *fwreq);
static struct brcmf_fw_request *
@ -802,30 +875,29 @@ static void brcmf_pcie_bus_console_read(struct brcmf_pciedev_info *devinfo,
static void brcmf_pcie_intr_disable(struct brcmf_pciedev_info *devinfo)
{
brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXMASK, 0);
brcmf_pcie_write_reg32(devinfo, devinfo->reginfo->mailboxmask, 0);
}
static void brcmf_pcie_intr_enable(struct brcmf_pciedev_info *devinfo)
{
brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXMASK,
BRCMF_PCIE_MB_INT_D2H_DB |
BRCMF_PCIE_MB_INT_FN0_0 |
BRCMF_PCIE_MB_INT_FN0_1);
brcmf_pcie_write_reg32(devinfo, devinfo->reginfo->mailboxmask,
devinfo->reginfo->int_d2h_db |
devinfo->reginfo->int_fn0);
}
static void brcmf_pcie_hostready(struct brcmf_pciedev_info *devinfo)
{
if (devinfo->shared.flags & BRCMF_PCIE_SHARED_HOSTRDY_DB1)
brcmf_pcie_write_reg32(devinfo,
BRCMF_PCIE_PCIE2REG_H2D_MAILBOX_1, 1);
devinfo->reginfo->h2d_mailbox_1, 1);
}
static irqreturn_t brcmf_pcie_quick_check_isr(int irq, void *arg)
{
struct brcmf_pciedev_info *devinfo = (struct brcmf_pciedev_info *)arg;
if (brcmf_pcie_read_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT)) {
if (brcmf_pcie_read_reg32(devinfo, devinfo->reginfo->mailboxint)) {
brcmf_pcie_intr_disable(devinfo);
brcmf_dbg(PCIE, "Enter\n");
return IRQ_WAKE_THREAD;
@ -840,15 +912,14 @@ static irqreturn_t brcmf_pcie_isr_thread(int irq, void *arg)
u32 status;
devinfo->in_irq = true;
status = brcmf_pcie_read_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT);
status = brcmf_pcie_read_reg32(devinfo, devinfo->reginfo->mailboxint);
brcmf_dbg(PCIE, "Enter %x\n", status);
if (status) {
brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT,
brcmf_pcie_write_reg32(devinfo, devinfo->reginfo->mailboxint,
status);
if (status & (BRCMF_PCIE_MB_INT_FN0_0 |
BRCMF_PCIE_MB_INT_FN0_1))
if (status & devinfo->reginfo->int_fn0)
brcmf_pcie_handle_mb_data(devinfo);
if (status & BRCMF_PCIE_MB_INT_D2H_DB) {
if (status & devinfo->reginfo->int_d2h_db) {
if (devinfo->state == BRCMFMAC_PCIE_STATE_UP)
brcmf_proto_msgbuf_rx_trigger(
&devinfo->pdev->dev);
@ -907,8 +978,8 @@ static void brcmf_pcie_release_irq(struct brcmf_pciedev_info *devinfo)
if (devinfo->in_irq)
brcmf_err(bus, "Still in IRQ (processing) !!!\n");
status = brcmf_pcie_read_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT);
brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT, status);
status = brcmf_pcie_read_reg32(devinfo, devinfo->reginfo->mailboxint);
brcmf_pcie_write_reg32(devinfo, devinfo->reginfo->mailboxint, status);
devinfo->irq_allocated = false;
}
@ -960,7 +1031,7 @@ static int brcmf_pcie_ring_mb_ring_bell(void *ctx)
brcmf_dbg(PCIE, "RING !\n");
/* Any arbitrary value will do, lets use 1 */
brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_H2D_MAILBOX_0, 1);
brcmf_pcie_write_reg32(devinfo, devinfo->reginfo->h2d_mailbox_0, 1);
return 0;
}
@ -1723,15 +1794,22 @@ static int brcmf_pcie_buscoreprep(void *ctx)
static int brcmf_pcie_buscore_reset(void *ctx, struct brcmf_chip *chip)
{
struct brcmf_pciedev_info *devinfo = (struct brcmf_pciedev_info *)ctx;
u32 val;
struct brcmf_core *core;
u32 val, reg;
devinfo->ci = chip;
brcmf_pcie_reset_device(devinfo);
val = brcmf_pcie_read_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT);
/* reginfo is not ready yet */
core = brcmf_chip_get_core(chip, BCMA_CORE_PCIE2);
if (core->rev >= 64)
reg = BRCMF_PCIE_64_PCIE2REG_MAILBOXINT;
else
reg = BRCMF_PCIE_PCIE2REG_MAILBOXINT;
val = brcmf_pcie_read_reg32(devinfo, reg);
if (val != 0xffffffff)
brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT,
val);
brcmf_pcie_write_reg32(devinfo, reg, val);
return 0;
}
@ -2117,6 +2195,7 @@ brcmf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
struct brcmf_fw_request *fwreq;
struct brcmf_pciedev_info *devinfo;
struct brcmf_pciedev *pcie_bus_dev;
struct brcmf_core *core;
struct brcmf_bus *bus;
brcmf_dbg(PCIE, "Enter %x:%x\n", pdev->vendor, pdev->device);
@ -2136,6 +2215,12 @@ brcmf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto fail;
}
core = brcmf_chip_get_core(devinfo->ci, BCMA_CORE_PCIE2);
if (core->rev >= 64)
devinfo->reginfo = &brcmf_reginfo_64;
else
devinfo->reginfo = &brcmf_reginfo_default;
pcie_bus_dev = kzalloc(sizeof(*pcie_bus_dev), GFP_KERNEL);
if (pcie_bus_dev == NULL) {
ret = -ENOMEM;
@ -2305,7 +2390,7 @@ static int brcmf_pcie_pm_leave_D3(struct device *dev)
brcmf_dbg(PCIE, "Enter, dev=%p, bus=%p\n", dev, bus);
/* Check if device is still up and running, if so we are ready */
if (brcmf_pcie_read_reg32(devinfo, BRCMF_PCIE_PCIE2REG_INTMASK) != 0) {
if (brcmf_pcie_read_reg32(devinfo, devinfo->reginfo->intmask) != 0) {
brcmf_dbg(PCIE, "Try to wakeup device....\n");
if (brcmf_pcie_send_mb_data(devinfo, BRCMF_H2D_HOST_D0_INFORM))
goto cleanup;