Commit cb7cf7be authored by Arend van Spriel's avatar Arend van Spriel Committed by John W. Linville
Browse files

brcmfmac: make chip related functions host interface independent



This patch make several chip related functions host interface
independent by defining callback interface struct brcmf_buscore_ops.

Reviewed-by: default avatarFranky (Zhenhui) Lin <frankyl@broadcom.com>
Reviewed-by: default avatarHante Meuleman <meuleman@broadcom.com>
Reviewed-by: default avatarPieter-Paul Giesberts <pieterpg@broadcom.com>
Reviewed-by: default avatarDaniel (Deognyoun) Kim <dekim@broadcom.com>
Signed-off-by: default avatarArend van Spriel <arend@broadcom.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent e0c180ec
Loading
Loading
Loading
Loading
+639 −511

File changed.

Preview size limit exceeded, changes collapsed.

+61 −198
Original line number Original line Diff line number Diff line
/*
/*
 * Copyright (c) 2011 Broadcom Corporation
 * Copyright (c) 2014 Broadcom Corporation
 *
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * purpose with or without fee is hereby granted, provided that the above
@@ -13,216 +13,79 @@
 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */
 */
#ifndef BRCMF_CHIP_H
#define BRCMF_CHIP_H


#ifndef _BRCMFMAC_SDIO_CHIP_H_
#include <linux/types.h>
#define _BRCMFMAC_SDIO_CHIP_H_


/*
 * Core reg address translation.
 * Both macro's returns a 32 bits byte address on the backplane bus.
 */
#define CORE_CC_REG(base, field) \
#define CORE_CC_REG(base, field) \
		(base + offsetof(struct chipcregs, field))
		(base + offsetof(struct chipcregs, field))
#define CORE_BUS_REG(base, field) \
		(base + offsetof(struct sdpcmd_regs, field))
#define CORE_SB(base, field) \
		(base + SBCONFIGOFF + offsetof(struct sbconfig, field))

/* SDIO function 1 register CHIPCLKCSR */
/* Force ALP request to backplane */
#define SBSDIO_FORCE_ALP		0x01
/* Force HT request to backplane */
#define SBSDIO_FORCE_HT			0x02
/* Force ILP request to backplane */
#define SBSDIO_FORCE_ILP		0x04
/* Make ALP ready (power up xtal) */
#define SBSDIO_ALP_AVAIL_REQ		0x08
/* Make HT ready (power up PLL) */
#define SBSDIO_HT_AVAIL_REQ		0x10
/* Squelch clock requests from HW */
#define SBSDIO_FORCE_HW_CLKREQ_OFF	0x20
/* Status: ALP is ready */
#define SBSDIO_ALP_AVAIL		0x40
/* Status: HT is ready */
#define SBSDIO_HT_AVAIL			0x80
#define SBSDIO_AVBITS		(SBSDIO_HT_AVAIL | SBSDIO_ALP_AVAIL)
#define SBSDIO_ALPAV(regval)	((regval) & SBSDIO_AVBITS)
#define SBSDIO_HTAV(regval)	(((regval) & SBSDIO_AVBITS) == SBSDIO_AVBITS)
#define SBSDIO_ALPONLY(regval)	(SBSDIO_ALPAV(regval) && !SBSDIO_HTAV(regval))
#define SBSDIO_CLKAV(regval, alponly) \
	(SBSDIO_ALPAV(regval) && (alponly ? 1 : SBSDIO_HTAV(regval)))

#define BRCMF_MAX_CORENUM	6

struct brcmf_core {
	u16 id;
	u16 rev;
	u32 base;
	u32 wrapbase;
	u32 caps;
	u32 cib;
};


/**
 * struct brcmf_chip - chip level information.
 *
 * @chip: chip identifier.
 * @chiprev: chip revision.
 * @cc_caps: chipcommon core capabilities.
 * @pmucaps: PMU capabilities.
 * @pmurev: PMU revision.
 * @rambase: RAM base address (only applicable for ARM CR4 chips).
 * @ramsize: amount of RAM on chip.
 * @name: string representation of the chip identifier.
 */
struct brcmf_chip {
struct brcmf_chip {
	u32 chip;
	u32 chip;
	u32 chiprev;
	u32 chiprev;
	/* core info */
	u32 cc_caps;
	/* always put chipcommon core at 0, bus core at 1 */
	struct brcmf_core c_inf[BRCMF_MAX_CORENUM];
	u32 pmurev;
	u32 pmucaps;
	u32 pmucaps;
	u32 ramsize;
	u32 pmurev;
	u32 rambase;
	u32 rambase;
	u32 rst_vec;	/* reset vertor for ARM CR4 core */
	u32 ramsize;

	char name[8];
	bool (*iscoreup)(struct brcmf_sdio_dev *sdiodev, struct brcmf_chip *ci,
			 u16 coreid);
	u32 (*corerev)(struct brcmf_sdio_dev *sdiodev, struct brcmf_chip *ci,
			 u16 coreid);
	void (*coredisable)(struct brcmf_sdio_dev *sdiodev,
			struct brcmf_chip *ci, u16 coreid, u32 pre_resetbits,
			u32 in_resetbits);
	void (*resetcore)(struct brcmf_sdio_dev *sdiodev,
			struct brcmf_chip *ci, u16 coreid, u32 pre_resetbits,
			u32 in_resetbits, u32 post_resetbits);
};
};


struct sbconfig {
/**
	u32 PAD[2];
 * struct brcmf_core - core related information.
	u32 sbipsflag;	/* initiator port ocp slave flag */
 *
	u32 PAD[3];
 * @id: core identifier.
	u32 sbtpsflag;	/* target port ocp slave flag */
 * @rev: core revision.
	u32 PAD[11];
 * @base: base address of core register space.
	u32 sbtmerrloga;	/* (sonics >= 2.3) */
 */
	u32 PAD;
struct brcmf_core {
	u32 sbtmerrlog;	/* (sonics >= 2.3) */
	u16 id;
	u32 PAD[3];
	u16 rev;
	u32 sbadmatch3;	/* address match3 */
	u32 base;
	u32 PAD;
	u32 sbadmatch2;	/* address match2 */
	u32 PAD;
	u32 sbadmatch1;	/* address match1 */
	u32 PAD[7];
	u32 sbimstate;	/* initiator agent state */
	u32 sbintvec;	/* interrupt mask */
	u32 sbtmstatelow;	/* target state */
	u32 sbtmstatehigh;	/* target state */
	u32 sbbwa0;		/* bandwidth allocation table0 */
	u32 PAD;
	u32 sbimconfiglow;	/* initiator configuration */
	u32 sbimconfighigh;	/* initiator configuration */
	u32 sbadmatch0;	/* address match0 */
	u32 PAD;
	u32 sbtmconfiglow;	/* target configuration */
	u32 sbtmconfighigh;	/* target configuration */
	u32 sbbconfig;	/* broadcast configuration */
	u32 PAD;
	u32 sbbstate;	/* broadcast state */
	u32 PAD[3];
	u32 sbactcnfg;	/* activate configuration */
	u32 PAD[3];
	u32 sbflagst;	/* current sbflags */
	u32 PAD[3];
	u32 sbidlow;		/* identification */
	u32 sbidhigh;	/* identification */
};
};


/* sdio core registers */
/**
struct sdpcmd_regs {
 * struct brcmf_buscore_ops - buscore specific callbacks.
	u32 corecontrol;		/* 0x00, rev8 */
 *
	u32 corestatus;			/* rev8 */
 * @read32: read 32-bit value over bus.
	u32 PAD[1];
 * @write32: write 32-bit value over bus.
	u32 biststatus;			/* rev8 */
 * @prepare: prepare bus for core configuration.

 * @setup: bus-specific core setup.
	/* PCMCIA access */
 * @exit_dl: exit download state.
	u16 pcmciamesportaladdr;	/* 0x010, rev8 */
 *	The callback should use the provided @rstvec when non-zero.
	u16 PAD[1];
 */
	u16 pcmciamesportalmask;	/* rev8 */
struct brcmf_buscore_ops {
	u16 PAD[1];
	u32 (*read32)(void *ctx, u32 addr);
	u16 pcmciawrframebc;		/* rev8 */
	void (*write32)(void *ctx, u32 addr, u32 value);
	u16 PAD[1];
	int (*prepare)(void *ctx);
	u16 pcmciaunderflowtimer;	/* rev8 */
	int (*setup)(void *ctx, struct brcmf_chip *chip);
	u16 PAD[1];
	void (*exit_dl)(void *ctx, struct brcmf_chip *chip, u32 rstvec);

	/* interrupt */
	u32 intstatus;			/* 0x020, rev8 */
	u32 hostintmask;		/* rev8 */
	u32 intmask;			/* rev8 */
	u32 sbintstatus;		/* rev8 */
	u32 sbintmask;			/* rev8 */
	u32 funcintmask;		/* rev4 */
	u32 PAD[2];
	u32 tosbmailbox;		/* 0x040, rev8 */
	u32 tohostmailbox;		/* rev8 */
	u32 tosbmailboxdata;		/* rev8 */
	u32 tohostmailboxdata;		/* rev8 */

	/* synchronized access to registers in SDIO clock domain */
	u32 sdioaccess;			/* 0x050, rev8 */
	u32 PAD[3];

	/* PCMCIA frame control */
	u8 pcmciaframectrl;		/* 0x060, rev8 */
	u8 PAD[3];
	u8 pcmciawatermark;		/* rev8 */
	u8 PAD[155];

	/* interrupt batching control */
	u32 intrcvlazy;			/* 0x100, rev8 */
	u32 PAD[3];

	/* counters */
	u32 cmd52rd;			/* 0x110, rev8 */
	u32 cmd52wr;			/* rev8 */
	u32 cmd53rd;			/* rev8 */
	u32 cmd53wr;			/* rev8 */
	u32 abort;			/* rev8 */
	u32 datacrcerror;		/* rev8 */
	u32 rdoutofsync;		/* rev8 */
	u32 wroutofsync;		/* rev8 */
	u32 writebusy;			/* rev8 */
	u32 readwait;			/* rev8 */
	u32 readterm;			/* rev8 */
	u32 writeterm;			/* rev8 */
	u32 PAD[40];
	u32 clockctlstatus;		/* rev8 */
	u32 PAD[7];

	u32 PAD[128];			/* DMA engines */

	/* SDIO/PCMCIA CIS region */
	char cis[512];			/* 0x400-0x5ff, rev6 */

	/* PCMCIA function control registers */
	char pcmciafcr[256];		/* 0x600-6ff, rev6 */
	u16 PAD[55];

	/* PCMCIA backplane access */
	u16 backplanecsr;		/* 0x76E, rev6 */
	u16 backplaneaddr0;		/* rev6 */
	u16 backplaneaddr1;		/* rev6 */
	u16 backplaneaddr2;		/* rev6 */
	u16 backplaneaddr3;		/* rev6 */
	u16 backplanedata0;		/* rev6 */
	u16 backplanedata1;		/* rev6 */
	u16 backplanedata2;		/* rev6 */
	u16 backplanedata3;		/* rev6 */
	u16 PAD[31];

	/* sprom "size" & "blank" info */
	u16 spromstatus;		/* 0x7BE, rev2 */
	u32 PAD[464];

	u16 PAD[0x80];
};
};


int brcmf_sdio_chip_attach(struct brcmf_sdio_dev *sdiodev,
struct brcmf_chip *brcmf_chip_attach(void *ctx,
			   struct brcmf_chip **ci_ptr);
				     const struct brcmf_buscore_ops *ops);
void brcmf_sdio_chip_detach(struct brcmf_chip **ci_ptr);
void brcmf_chip_detach(struct brcmf_chip *chip);
u8 brcmf_sdio_chip_getinfidx(struct brcmf_chip *ci, u16 coreid);
struct brcmf_core *brcmf_chip_get_core(struct brcmf_chip *chip, u16 coreid);
void brcmf_sdio_chip_enter_download(struct brcmf_sdio_dev *sdiodev,
struct brcmf_core *brcmf_chip_get_chipcommon(struct brcmf_chip *chip);
				    struct brcmf_chip *ci);
bool brcmf_chip_iscoreup(struct brcmf_core *core);
bool brcmf_sdio_chip_exit_download(struct brcmf_sdio_dev *sdiodev,
void brcmf_chip_coredisable(struct brcmf_core *core, u32 prereset, u32 reset);
				   struct brcmf_chip *ci, u32 rstvec);
void brcmf_chip_resetcore(struct brcmf_core *core, u32 prereset, u32 reset,

			  u32 postreset);
#endif		/* _BRCMFMAC_SDIO_CHIP_H_ */
void brcmf_chip_enter_download(struct brcmf_chip *ci);
bool brcmf_chip_exit_download(struct brcmf_chip *ci, u32 rstvec);
bool brcmf_chip_sr_capable(struct brcmf_chip *pub);

#endif /* BRCMF_AXIDMP_H */
+111 −89
Original line number Original line Diff line number Diff line
@@ -23,6 +23,7 @@
#include <linux/interrupt.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/sched.h>
#include <linux/mmc/sdio.h>
#include <linux/mmc/sdio.h>
#include <linux/mmc/sdio_ids.h>
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/card.h>
#include <linux/mmc/card.h>
#include <linux/semaphore.h>
#include <linux/semaphore.h>
@@ -156,6 +157,33 @@ struct rte_console {
/* manfid tuple length, include tuple, link bytes */
/* manfid tuple length, include tuple, link bytes */
#define SBSDIO_CIS_MANFID_TUPLE_LEN	6
#define SBSDIO_CIS_MANFID_TUPLE_LEN	6


#define CORE_BUS_REG(base, field) \
		(base + offsetof(struct sdpcmd_regs, field))

/* SDIO function 1 register CHIPCLKCSR */
/* Force ALP request to backplane */
#define SBSDIO_FORCE_ALP		0x01
/* Force HT request to backplane */
#define SBSDIO_FORCE_HT			0x02
/* Force ILP request to backplane */
#define SBSDIO_FORCE_ILP		0x04
/* Make ALP ready (power up xtal) */
#define SBSDIO_ALP_AVAIL_REQ		0x08
/* Make HT ready (power up PLL) */
#define SBSDIO_HT_AVAIL_REQ		0x10
/* Squelch clock requests from HW */
#define SBSDIO_FORCE_HW_CLKREQ_OFF	0x20
/* Status: ALP is ready */
#define SBSDIO_ALP_AVAIL		0x40
/* Status: HT is ready */
#define SBSDIO_HT_AVAIL			0x80
#define SBSDIO_AVBITS		(SBSDIO_HT_AVAIL | SBSDIO_ALP_AVAIL)
#define SBSDIO_ALPAV(regval)	((regval) & SBSDIO_AVBITS)
#define SBSDIO_HTAV(regval)	(((regval) & SBSDIO_AVBITS) == SBSDIO_AVBITS)
#define SBSDIO_ALPONLY(regval)	(SBSDIO_ALPAV(regval) && !SBSDIO_HTAV(regval))
#define SBSDIO_CLKAV(regval, alponly) \
	(SBSDIO_ALPAV(regval) && (alponly ? 1 : SBSDIO_HTAV(regval)))

/* intstatus */
/* intstatus */
#define I_SMB_SW0	(1 << 0)	/* To SB Mail S/W interrupt 0 */
#define I_SMB_SW0	(1 << 0)	/* To SB Mail S/W interrupt 0 */
#define I_SMB_SW1	(1 << 1)	/* To SB Mail S/W interrupt 1 */
#define I_SMB_SW1	(1 << 1)	/* To SB Mail S/W interrupt 1 */
@@ -665,27 +693,24 @@ static bool data_ok(struct brcmf_sdio *bus)
 * Reads a register in the SDIO hardware block. This block occupies a series of
 * Reads a register in the SDIO hardware block. This block occupies a series of
 * adresses on the 32 bit backplane bus.
 * adresses on the 32 bit backplane bus.
 */
 */
static int
static int r_sdreg32(struct brcmf_sdio *bus, u32 *regvar, u32 offset)
r_sdreg32(struct brcmf_sdio *bus, u32 *regvar, u32 offset)
{
{
	u8 idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV);
	struct brcmf_core *core;
	int ret;
	int ret;


	*regvar = brcmf_sdiod_regrl(bus->sdiodev,
	core = brcmf_chip_get_core(bus->ci, BCMA_CORE_SDIO_DEV);
				    bus->ci->c_inf[idx].base + offset, &ret);
	*regvar = brcmf_sdiod_regrl(bus->sdiodev, core->base + offset, &ret);


	return ret;
	return ret;
}
}


static int
static int w_sdreg32(struct brcmf_sdio *bus, u32 regval, u32 reg_offset)
w_sdreg32(struct brcmf_sdio *bus, u32 regval, u32 reg_offset)
{
{
	u8 idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV);
	struct brcmf_core *core;
	int ret;
	int ret;


	brcmf_sdiod_regwl(bus->sdiodev,
	core = brcmf_chip_get_core(bus->ci, BCMA_CORE_SDIO_DEV);
			  bus->ci->c_inf[idx].base + reg_offset,
	brcmf_sdiod_regwl(bus->sdiodev, core->base + reg_offset, regval, &ret);
			  regval, &ret);


	return ret;
	return ret;
}
}
@@ -2425,14 +2450,13 @@ static inline void brcmf_sdio_clrintr(struct brcmf_sdio *bus)


static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus)
static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus)
{
{
	u8 idx;
	struct brcmf_core *buscore;
	u32 addr;
	u32 addr;
	unsigned long val;
	unsigned long val;
	int n, ret;
	int n, ret;


	idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV);
	buscore = brcmf_chip_get_core(bus->ci, BCMA_CORE_SDIO_DEV);
	addr = bus->ci->c_inf[idx].base +
	addr = buscore->base + offsetof(struct sdpcmd_regs, intstatus);
	       offsetof(struct sdpcmd_regs, intstatus);


	val = brcmf_sdiod_regrl(bus->sdiodev, addr, &ret);
	val = brcmf_sdiod_regrl(bus->sdiodev, addr, &ret);
	bus->sdcnt.f1regdata++;
	bus->sdcnt.f1regdata++;
@@ -3344,7 +3368,7 @@ static int brcmf_sdio_download_firmware(struct brcmf_sdio *bus)
	brcmf_sdio_clkctl(bus, CLK_AVAIL, false);
	brcmf_sdio_clkctl(bus, CLK_AVAIL, false);


	/* Keep arm in reset */
	/* Keep arm in reset */
	brcmf_sdio_chip_enter_download(bus->sdiodev, bus->ci);
	brcmf_chip_enter_download(bus->ci);


	fw = brcmf_sdio_get_fw(bus, BRCMF_FIRMWARE_BIN);
	fw = brcmf_sdio_get_fw(bus, BRCMF_FIRMWARE_BIN);
	if (fw == NULL) {
	if (fw == NULL) {
@@ -3376,7 +3400,7 @@ static int brcmf_sdio_download_firmware(struct brcmf_sdio *bus)
	}
	}


	/* Take arm out of reset */
	/* Take arm out of reset */
	if (!brcmf_sdio_chip_exit_download(bus->sdiodev, bus->ci, rstvec)) {
	if (!brcmf_chip_exit_download(bus->ci, rstvec)) {
		brcmf_err("error getting out of ARM core reset\n");
		brcmf_err("error getting out of ARM core reset\n");
		goto err;
		goto err;
	}
	}
@@ -3391,40 +3415,6 @@ err:
	return bcmerror;
	return bcmerror;
}
}


static bool brcmf_sdio_sr_capable(struct brcmf_sdio *bus)
{
	u32 addr, reg, pmu_cc3_mask = ~0;
	int err;

	brcmf_dbg(TRACE, "Enter\n");

	/* old chips with PMU version less than 17 don't support save restore */
	if (bus->ci->pmurev < 17)
		return false;

	switch (bus->ci->chip) {
	case BCM43241_CHIP_ID:
	case BCM4335_CHIP_ID:
	case BCM4339_CHIP_ID:
		/* read PMU chipcontrol register 3 */
		addr = CORE_CC_REG(bus->ci->c_inf[0].base, chipcontrol_addr);
		brcmf_sdiod_regwl(bus->sdiodev, addr, 3, NULL);
		addr = CORE_CC_REG(bus->ci->c_inf[0].base, chipcontrol_data);
		reg = brcmf_sdiod_regrl(bus->sdiodev, addr, NULL);
		return (reg & pmu_cc3_mask) != 0;
	default:
		addr = CORE_CC_REG(bus->ci->c_inf[0].base, pmucapabilities_ext);
		reg = brcmf_sdiod_regrl(bus->sdiodev, addr, &err);
		if ((reg & PCAPEXT_SR_SUPPORTED_MASK) == 0)
			return false;

		addr = CORE_CC_REG(bus->ci->c_inf[0].base, retention_ctl);
		reg = brcmf_sdiod_regrl(bus->sdiodev, addr, NULL);
		return (reg & (PMU_RCTL_MACPHY_DISABLE_MASK |
			       PMU_RCTL_LOGIC_DISABLE_MASK)) == 0;
	}
}

static void brcmf_sdio_sr_init(struct brcmf_sdio *bus)
static void brcmf_sdio_sr_init(struct brcmf_sdio *bus)
{
{
	int err = 0;
	int err = 0;
@@ -3476,7 +3466,7 @@ static int brcmf_sdio_kso_init(struct brcmf_sdio *bus)
	brcmf_dbg(TRACE, "Enter\n");
	brcmf_dbg(TRACE, "Enter\n");


	/* KSO bit added in SDIO core rev 12 */
	/* KSO bit added in SDIO core rev 12 */
	if (bus->ci->c_inf[1].rev < 12)
	if (brcmf_chip_get_core(bus->ci, BCMA_CORE_SDIO_DEV)->rev < 12)
		return 0;
		return 0;


	val = brcmf_sdiod_regrb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR, &err);
	val = brcmf_sdiod_regrb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR, &err);
@@ -3507,15 +3497,13 @@ static int brcmf_sdio_bus_preinit(struct device *dev)
	struct brcmf_sdio *bus = sdiodev->bus;
	struct brcmf_sdio *bus = sdiodev->bus;
	uint pad_size;
	uint pad_size;
	u32 value;
	u32 value;
	u8 idx;
	int err;
	int err;


	/* the commands below use the terms tx and rx from
	/* the commands below use the terms tx and rx from
	 * a device perspective, ie. bus:txglom affects the
	 * a device perspective, ie. bus:txglom affects the
	 * bus transfers from device to host.
	 * bus transfers from device to host.
	 */
	 */
	idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV);
	if (brcmf_chip_get_core(bus->ci, BCMA_CORE_SDIO_DEV)->rev < 12) {
	if (bus->ci->c_inf[idx].rev < 12) {
		/* for sdio core rev < 12, disable txgloming */
		/* for sdio core rev < 12, disable txgloming */
		value = 0;
		value = 0;
		err = brcmf_iovar_data_set(dev, "bus:txglom", &value,
		err = brcmf_iovar_data_set(dev, "bus:txglom", &value,
@@ -3626,7 +3614,7 @@ static int brcmf_sdio_bus_init(struct device *dev)
		ret = -ENODEV;
		ret = -ENODEV;
	}
	}


	if (brcmf_sdio_sr_capable(bus)) {
	if (brcmf_chip_sr_capable(bus->ci)) {
		brcmf_sdio_sr_init(bus);
		brcmf_sdio_sr_init(bus);
	} else {
	} else {
		/* Restore previous clock setting */
		/* Restore previous clock setting */
@@ -3775,15 +3763,6 @@ static void brcmf_sdio_dataworker(struct work_struct *work)
	}
	}
}
}


static char *brcmf_sdio_chip_name(uint chipid, char *buf, uint len)
{
	const char *fmt;

	fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
	snprintf(buf, len, fmt, chipid);
	return buf;
}

static void
static void
brcmf_sdio_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
brcmf_sdio_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
			     struct brcmf_chip *ci, u32 drivestrength)
			     struct brcmf_chip *ci, u32 drivestrength)
@@ -3791,14 +3770,13 @@ brcmf_sdio_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
	const struct sdiod_drive_str *str_tab = NULL;
	const struct sdiod_drive_str *str_tab = NULL;
	u32 str_mask;
	u32 str_mask;
	u32 str_shift;
	u32 str_shift;
	char chn[8];
	u32 base;
	u32 base = ci->c_inf[0].base;
	u32 i;
	u32 i;
	u32 drivestrength_sel = 0;
	u32 drivestrength_sel = 0;
	u32 cc_data_temp;
	u32 cc_data_temp;
	u32 addr;
	u32 addr;


	if (!(ci->c_inf[0].caps & CC_CAP_PMU))
	if (!(ci->cc_caps & CC_CAP_PMU))
		return;
		return;


	switch (SDIOD_DRVSTR_KEY(ci->chip, ci->pmurev)) {
	switch (SDIOD_DRVSTR_KEY(ci->chip, ci->pmurev)) {
@@ -3821,8 +3799,7 @@ brcmf_sdio_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
			str_shift = 0;
			str_shift = 0;
		} else
		} else
			brcmf_err("Invalid SDIO Drive strength for chip %s, strength=%d\n",
			brcmf_err("Invalid SDIO Drive strength for chip %s, strength=%d\n",
				  brcmf_sdio_chip_name(ci->chip, chn, 8),
				  ci->name, drivestrength);
				  drivestrength);
		break;
		break;
	case SDIOD_DRVSTR_KEY(BCM43362_CHIP_ID, 13):
	case SDIOD_DRVSTR_KEY(BCM43362_CHIP_ID, 13):
		str_tab = sdiod_drive_strength_tab5_1v8;
		str_tab = sdiod_drive_strength_tab5_1v8;
@@ -3831,8 +3808,7 @@ brcmf_sdio_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
		break;
		break;
	default:
	default:
		brcmf_err("No SDIO Drive strength init done for chip %s rev %d pmurev %d\n",
		brcmf_err("No SDIO Drive strength init done for chip %s rev %d pmurev %d\n",
			  brcmf_sdio_chip_name(ci->chip, chn, 8),
			  ci->name, ci->chiprev, ci->pmurev);
			  ci->chiprev, ci->pmurev);
		break;
		break;
	}
	}


@@ -3843,6 +3819,7 @@ brcmf_sdio_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
				break;
				break;
			}
			}
		}
		}
		base = brcmf_chip_get_chipcommon(ci)->base;
		addr = CORE_CC_REG(base, chipcontrol_addr);
		addr = CORE_CC_REG(base, chipcontrol_addr);
		brcmf_sdiod_regwl(sdiodev, addr, 1, NULL);
		brcmf_sdiod_regwl(sdiodev, addr, 1, NULL);
		cc_data_temp = brcmf_sdiod_regrl(sdiodev, addr, NULL);
		cc_data_temp = brcmf_sdiod_regrl(sdiodev, addr, NULL);
@@ -3856,8 +3833,9 @@ brcmf_sdio_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
	}
	}
}
}


int brcmf_sdio_buscoreprep(struct brcmf_sdio_dev *sdiodev)
static int brcmf_sdio_buscoreprep(void *ctx)
{
{
	struct brcmf_sdio_dev *sdiodev = ctx;
	int err = 0;
	int err = 0;
	u8 clkval, clkset;
	u8 clkval, clkset;


@@ -3900,6 +3878,55 @@ int brcmf_sdio_buscoreprep(struct brcmf_sdio_dev *sdiodev)
	return 0;
	return 0;
}
}


static void brcmf_sdio_buscore_exitdl(void *ctx, struct brcmf_chip *chip,
				      u32 rstvec)
{
	struct brcmf_sdio_dev *sdiodev = ctx;
	struct brcmf_core *core;
	u32 reg_addr;

	/* clear all interrupts */
	core = brcmf_chip_get_core(chip, BCMA_CORE_SDIO_DEV);
	reg_addr = core->base + offsetof(struct sdpcmd_regs, intstatus);
	brcmf_sdiod_regwl(sdiodev, reg_addr, 0xFFFFFFFF, NULL);

	if (rstvec)
		/* Write reset vector to address 0 */
		brcmf_sdiod_ramrw(sdiodev, true, 0, (void *)&rstvec,
				  sizeof(rstvec));
}

static u32 brcmf_sdio_buscore_read32(void *ctx, u32 addr)
{
	struct brcmf_sdio_dev *sdiodev = ctx;
	u32 val, rev;

	val = brcmf_sdiod_regrl(sdiodev, addr, NULL);
	if (sdiodev->func[0]->device == SDIO_DEVICE_ID_BROADCOM_4335_4339 &&
	    addr == CORE_CC_REG(SI_ENUM_BASE, chipid)) {
		rev = (val & CID_REV_MASK) >> CID_REV_SHIFT;
		if (rev >= 2) {
			val &= ~CID_ID_MASK;
			val |= BCM4339_CHIP_ID;
		}
	}
	return val;
}

static void brcmf_sdio_buscore_write32(void *ctx, u32 addr, u32 val)
{
	struct brcmf_sdio_dev *sdiodev = ctx;

	brcmf_sdiod_regwl(sdiodev, addr, val, NULL);
}

static const struct brcmf_buscore_ops brcmf_sdio_buscore_ops = {
	.prepare = brcmf_sdio_buscoreprep,
	.exit_dl = brcmf_sdio_buscore_exitdl,
	.read32 = brcmf_sdio_buscore_read32,
	.write32 = brcmf_sdio_buscore_write32,
};

static bool
static bool
brcmf_sdio_probe_attach(struct brcmf_sdio *bus)
brcmf_sdio_probe_attach(struct brcmf_sdio *bus)
{
{
@@ -3915,7 +3942,7 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus)
		 brcmf_sdiod_regrl(bus->sdiodev, SI_ENUM_BASE, NULL));
		 brcmf_sdiod_regrl(bus->sdiodev, SI_ENUM_BASE, NULL));


	/*
	/*
	 * Force PLL off until brcmf_sdio_chip_attach()
	 * Force PLL off until brcmf_chip_attach()
	 * programs PLL control regs
	 * programs PLL control regs
	 */
	 */


@@ -3936,8 +3963,10 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus)
	 */
	 */
	brcmf_bus_change_state(bus->sdiodev->bus_if, BRCMF_BUS_DOWN);
	brcmf_bus_change_state(bus->sdiodev->bus_if, BRCMF_BUS_DOWN);


	if (brcmf_sdio_chip_attach(bus->sdiodev, &bus->ci)) {
	bus->ci = brcmf_chip_attach(bus->sdiodev, &brcmf_sdio_buscore_ops);
		brcmf_err("brcmf_sdio_chip_attach failed!\n");
	if (IS_ERR(bus->ci)) {
		brcmf_err("brcmf_chip_attach failed!\n");
		bus->ci = NULL;
		goto fail;
		goto fail;
	}
	}


@@ -3973,24 +4002,18 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus)
		goto fail;
		goto fail;


	/* set PMUControl so a backplane reset does PMU state reload */
	/* set PMUControl so a backplane reset does PMU state reload */
	reg_addr = CORE_CC_REG(bus->ci->c_inf[0].base,
	reg_addr = CORE_CC_REG(brcmf_chip_get_chipcommon(bus->ci)->base,
			       pmucontrol);
			       pmucontrol);
	reg_val = brcmf_sdiod_regrl(bus->sdiodev,
	reg_val = brcmf_sdiod_regrl(bus->sdiodev, reg_addr, &err);
				    reg_addr,
				    &err);
	if (err)
	if (err)
		goto fail;
		goto fail;


	reg_val |= (BCMA_CC_PMU_CTL_RES_RELOAD << BCMA_CC_PMU_CTL_RES_SHIFT);
	reg_val |= (BCMA_CC_PMU_CTL_RES_RELOAD << BCMA_CC_PMU_CTL_RES_SHIFT);


	brcmf_sdiod_regwl(bus->sdiodev,
	brcmf_sdiod_regwl(bus->sdiodev, reg_addr, reg_val, &err);
			  reg_addr,
			  reg_val,
			  &err);
	if (err)
	if (err)
		goto fail;
		goto fail;



	sdio_release_host(bus->sdiodev->func[1]);
	sdio_release_host(bus->sdiodev->func[1]);


	brcmu_pktq_init(&bus->txq, (PRIOMASK + 1), TXQLEN);
	brcmu_pktq_init(&bus->txq, (PRIOMASK + 1), TXQLEN);
@@ -4223,12 +4246,11 @@ void brcmf_sdio_remove(struct brcmf_sdio *bus)
				 * all necessary cores.
				 * all necessary cores.
				 */
				 */
				msleep(20);
				msleep(20);
				brcmf_sdio_chip_enter_download(bus->sdiodev,
				brcmf_chip_enter_download(bus->ci);
							       bus->ci);
				brcmf_sdio_clkctl(bus, CLK_NONE, false);
				brcmf_sdio_clkctl(bus, CLK_NONE, false);
				sdio_release_host(bus->sdiodev->func[1]);
				sdio_release_host(bus->sdiodev->func[1]);
			}
			}
			brcmf_sdio_chip_detach(&bus->ci);
			brcmf_chip_detach(bus->ci);
		}
		}


		brcmu_pkt_buf_free_skb(bus->txglom_sgpad);
		brcmu_pkt_buf_free_skb(bus->txglom_sgpad);
+89 −1
Original line number Original line Diff line number Diff line
@@ -182,6 +182,95 @@ struct brcmf_sdio_dev {
	uint max_segment_size;
	uint max_segment_size;
};
};


/* sdio core registers */
struct sdpcmd_regs {
	u32 corecontrol;		/* 0x00, rev8 */
	u32 corestatus;			/* rev8 */
	u32 PAD[1];
	u32 biststatus;			/* rev8 */

	/* PCMCIA access */
	u16 pcmciamesportaladdr;	/* 0x010, rev8 */
	u16 PAD[1];
	u16 pcmciamesportalmask;	/* rev8 */
	u16 PAD[1];
	u16 pcmciawrframebc;		/* rev8 */
	u16 PAD[1];
	u16 pcmciaunderflowtimer;	/* rev8 */
	u16 PAD[1];

	/* interrupt */
	u32 intstatus;			/* 0x020, rev8 */
	u32 hostintmask;		/* rev8 */
	u32 intmask;			/* rev8 */
	u32 sbintstatus;		/* rev8 */
	u32 sbintmask;			/* rev8 */
	u32 funcintmask;		/* rev4 */
	u32 PAD[2];
	u32 tosbmailbox;		/* 0x040, rev8 */
	u32 tohostmailbox;		/* rev8 */
	u32 tosbmailboxdata;		/* rev8 */
	u32 tohostmailboxdata;		/* rev8 */

	/* synchronized access to registers in SDIO clock domain */
	u32 sdioaccess;			/* 0x050, rev8 */
	u32 PAD[3];

	/* PCMCIA frame control */
	u8 pcmciaframectrl;		/* 0x060, rev8 */
	u8 PAD[3];
	u8 pcmciawatermark;		/* rev8 */
	u8 PAD[155];

	/* interrupt batching control */
	u32 intrcvlazy;			/* 0x100, rev8 */
	u32 PAD[3];

	/* counters */
	u32 cmd52rd;			/* 0x110, rev8 */
	u32 cmd52wr;			/* rev8 */
	u32 cmd53rd;			/* rev8 */
	u32 cmd53wr;			/* rev8 */
	u32 abort;			/* rev8 */
	u32 datacrcerror;		/* rev8 */
	u32 rdoutofsync;		/* rev8 */
	u32 wroutofsync;		/* rev8 */
	u32 writebusy;			/* rev8 */
	u32 readwait;			/* rev8 */
	u32 readterm;			/* rev8 */
	u32 writeterm;			/* rev8 */
	u32 PAD[40];
	u32 clockctlstatus;		/* rev8 */
	u32 PAD[7];

	u32 PAD[128];			/* DMA engines */

	/* SDIO/PCMCIA CIS region */
	char cis[512];			/* 0x400-0x5ff, rev6 */

	/* PCMCIA function control registers */
	char pcmciafcr[256];		/* 0x600-6ff, rev6 */
	u16 PAD[55];

	/* PCMCIA backplane access */
	u16 backplanecsr;		/* 0x76E, rev6 */
	u16 backplaneaddr0;		/* rev6 */
	u16 backplaneaddr1;		/* rev6 */
	u16 backplaneaddr2;		/* rev6 */
	u16 backplaneaddr3;		/* rev6 */
	u16 backplanedata0;		/* rev6 */
	u16 backplanedata1;		/* rev6 */
	u16 backplanedata2;		/* rev6 */
	u16 backplanedata3;		/* rev6 */
	u16 PAD[31];

	/* sprom "size" & "blank" info */
	u16 spromstatus;		/* 0x7BE, rev2 */
	u32 PAD[464];

	u16 PAD[0x80];
};

/* Register/deregister interrupt handler. */
/* Register/deregister interrupt handler. */
int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev);
int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev);
int brcmf_sdiod_intr_unregister(struct brcmf_sdio_dev *sdiodev);
int brcmf_sdiod_intr_unregister(struct brcmf_sdio_dev *sdiodev);
@@ -239,6 +328,5 @@ void brcmf_sdio_remove(struct brcmf_sdio *bus);
void brcmf_sdio_isr(struct brcmf_sdio *bus);
void brcmf_sdio_isr(struct brcmf_sdio *bus);


void brcmf_sdio_wd_timer(struct brcmf_sdio *bus, uint wdtick);
void brcmf_sdio_wd_timer(struct brcmf_sdio *bus, uint wdtick);
int brcmf_sdio_buscoreprep(struct brcmf_sdio_dev *sdiodev);


#endif				/* _BRCM_SDH_H_ */
#endif				/* _BRCM_SDH_H_ */