[PATCH 2/7] staging: brcm80211: Add dhdsdio_chip_attach in dhd_sdio.c

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



dhdsdio_chip_attach and it sub functions are added for si/sb utils removal.
It will replace si_attach in following patches.

Signed-off-by: Franky Lin <frankyl@xxxxxxxxxxxx>
---
 drivers/staging/brcm80211/brcmfmac/dhd_sdio.c |  253 +++++++++++++++++++++++++
 1 files changed, 253 insertions(+), 0 deletions(-)

diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c b/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c
index aad9965..75be99d 100644
--- a/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c
+++ b/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c
@@ -53,6 +53,7 @@
 #include <dhdioctl.h>
 #include <sdiovar.h>
 #include <siutils_priv.h>
+#include <bcmchip.h>
 
 #ifndef DHDSDIO_MEM_DUMP_FNAME
 #define DHDSDIO_MEM_DUMP_FNAME         "mem_dump"
@@ -166,12 +167,28 @@ typedef struct dhd_console {
 } dhd_console_t;
 #endif				/* DHD_DEBUG */
 
+/* misc chip info needed by some of the routines */
+struct chip_info {
+	u32 chip;
+	u32 chiprev;
+	u32 cccorebase;
+	u32 ccrev;
+	u32 cccaps;
+	u32 buscorebase;
+	u32 buscorerev;
+	u32 buscoretype;
+	u32 ramcorebase;
+	u32 armcorebase;
+	u32 pmurev;
+};
+
 /* Private data for SDIO bus interaction */
 typedef struct dhd_bus {
 	dhd_pub_t *dhd;
 
 	bcmsdh_info_t *sdh;	/* Handle for BCMSDH calls */
 	si_t *sih;		/* Handle for SI calls */
+	struct chip_info *ci;	/* Chip info struct */
 	char *vars;		/* Variables (from CIS and/or other) */
 	uint varsz;		/* Size of variables buffer */
 	u32 sbaddr;		/* Current SB window pointer (-1, invalid) */
@@ -465,6 +482,7 @@ static int dhdsdio_download_nvram(struct dhd_bus *bus);
 #ifdef BCMEMBEDIMAGE
 static int dhdsdio_download_code_array(struct dhd_bus *bus);
 #endif
+static int dhdsdio_chip_attach(struct dhd_bus *bus, void *regs);
 
 static void dhd_dongle_setmemsize(struct dhd_bus *bus, int mem_size)
 {
@@ -5289,6 +5307,10 @@ dhdsdio_probe_attach(struct dhd_bus *bus, void *sdh, void *regsva, u16 devid)
 		DHD_ERROR(("%s: si_attach failed!\n", __func__));
 		goto fail;
 	}
+	if (dhdsdio_chip_attach(bus, regsva)) {
+		DHD_ERROR(("%s: dhdsdio_chip_attach failed!\n", __func__));
+		goto fail;
+	}
 
 	bcmsdh_chipinfo(sdh, bus->sih->chip, bus->sih->chiprev);
 
@@ -6071,3 +6093,234 @@ int dhd_bus_devreset(dhd_pub_t *dhdp, u8 flag)
 	}
 	return bcmerror;
 }
+
+static int
+dhdsdio_chip_recognition(bcmsdh_info_t *sdh, struct chip_info *ci, void *regs)
+{
+	u32 regdata;
+
+	/*
+	 * Get CC core rev
+	 * Chipid is assume to be at offset 0 from regs arg
+	 * For different chiptypes or old sdio hosts w/o chipcommon,
+	 * other ways of recognition should be added here.
+	 */
+	ci->cccorebase = (u32)regs;
+	regdata = bcmsdh_reg_read(sdh, CORE_CC_REG(ci->cccorebase, chipid), 4);
+	ci->chip = regdata & CID_ID_MASK;
+	ci->chiprev = (regdata & CID_REV_MASK) >> CID_REV_SHIFT;
+
+	DHD_INFO(("%s: chipid=0x%x chiprev=%d\n",
+		__func__, ci->chip, ci->chiprev));
+
+	/* Address of cores for new chips should be added here */
+	switch (ci->chip) {
+	case BCM4329_CHIP_ID:
+		ci->buscorebase = BCM4329_CORE_BUS_BASE;
+		ci->ramcorebase = BCM4329_CORE_SOCRAM_BASE;
+		ci->armcorebase	= BCM4329_CORE_ARM_BASE;
+		break;
+	default:
+		DHD_ERROR(("%s: chipid 0x%x is not supported\n",
+			__func__, ci->chip));
+		return -ENODEV;
+	}
+
+	regdata = bcmsdh_reg_read(sdh,
+		CORE_SB(ci->cccorebase, sbidhigh), 4);
+	ci->ccrev = SBCOREREV(regdata);
+
+	regdata = bcmsdh_reg_read(sdh,
+		CORE_CC_REG(ci->cccorebase, pmucapabilities), 4);
+	ci->pmurev = regdata & PCAP_REV_MASK;
+
+	regdata = bcmsdh_reg_read(sdh, CORE_SB(ci->buscorebase, sbidhigh), 4);
+	ci->buscorerev = SBCOREREV(regdata);
+	ci->buscoretype = (regdata & SBIDH_CC_MASK) >> SBIDH_CC_SHIFT;
+
+	DHD_INFO(("%s: ccrev=%d, pmurev=%d, buscore rev/type=%d/0x%x\n",
+		__func__, ci->ccrev, ci->pmurev,
+		ci->buscorerev, ci->buscoretype));
+
+	/* get chipcommon capabilites */
+	ci->cccaps = bcmsdh_reg_read(sdh,
+		CORE_CC_REG(ci->cccorebase, capabilities), 4);
+
+	return 0;
+}
+
+static void
+dhdsdio_chip_disablecore(bcmsdh_info_t *sdh, u32 corebase)
+{
+	u32 regdata;
+
+	regdata = bcmsdh_reg_read(sdh,
+		CORE_SB(corebase, sbtmstatelow), 4);
+	if (regdata & SBTML_RESET)
+		return;
+
+	regdata = bcmsdh_reg_read(sdh,
+		CORE_SB(corebase, sbtmstatelow), 4);
+	if ((regdata & (SICF_CLOCK_EN << SBTML_SICF_SHIFT)) != 0) {
+		/*
+		 * set target reject and spin until busy is clear
+		 * (preserve core-specific bits)
+		 */
+		regdata = bcmsdh_reg_read(sdh,
+			CORE_SB(corebase, sbtmstatelow), 4);
+		bcmsdh_reg_write(sdh, CORE_SB(corebase, sbtmstatelow), 4,
+			regdata | SBTML_REJ);
+
+		regdata = bcmsdh_reg_read(sdh,
+			CORE_SB(corebase, sbtmstatelow), 4);
+		udelay(1);
+		SPINWAIT((bcmsdh_reg_read(sdh,
+			CORE_SB(corebase, sbtmstatehigh), 4) &
+			SBTMH_BUSY), 100000);
+
+		regdata = bcmsdh_reg_read(sdh,
+			CORE_SB(corebase, sbtmstatehigh), 4);
+		if (regdata & SBTMH_BUSY)
+			DHD_ERROR(("%s: ARM core still busy\n", __func__));
+
+		regdata = bcmsdh_reg_read(sdh,
+			CORE_SB(corebase, sbidlow), 4);
+		if (regdata & SBIDL_INIT) {
+			regdata = bcmsdh_reg_read(sdh,
+				CORE_SB(corebase, sbimstate), 4) |
+				SBIM_RJ;
+			bcmsdh_reg_write(sdh,
+				CORE_SB(corebase, sbimstate), 4,
+				regdata);
+			regdata = bcmsdh_reg_read(sdh,
+				CORE_SB(corebase, sbimstate), 4);
+			udelay(1);
+			SPINWAIT((bcmsdh_reg_read(sdh,
+				CORE_SB(corebase, sbimstate), 4) &
+				SBIM_BY), 100000);
+		}
+
+		/* set reset and reject while enabling the clocks */
+		bcmsdh_reg_write(sdh,
+			CORE_SB(corebase, sbtmstatelow), 4,
+			(((SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT) |
+			SBTML_REJ | SBTML_RESET));
+		regdata = bcmsdh_reg_read(sdh,
+			CORE_SB(corebase, sbtmstatelow), 4);
+		udelay(10);
+
+		/* clear the initiator reject bit */
+		regdata = bcmsdh_reg_read(sdh,
+			CORE_SB(corebase, sbidlow), 4);
+		if (regdata & SBIDL_INIT) {
+			regdata = bcmsdh_reg_read(sdh,
+				CORE_SB(corebase, sbimstate), 4) &
+				~SBIM_RJ;
+			bcmsdh_reg_write(sdh,
+				CORE_SB(corebase, sbimstate), 4,
+				regdata);
+		}
+	}
+
+	/* leave reset and reject asserted */
+	bcmsdh_reg_write(sdh, CORE_SB(corebase, sbtmstatelow), 4,
+		(SBTML_REJ | SBTML_RESET));
+	udelay(1);
+}
+
+static int
+dhdsdio_chip_attach(struct dhd_bus *bus, void *regs)
+{
+	struct chip_info *ci;
+	int err;
+	u8 clkval, clkset;
+
+	DHD_TRACE(("%s: Enter\n", __func__));
+
+	/* alloc chip_info_t */
+	ci = kmalloc(sizeof(struct chip_info), GFP_ATOMIC);
+	if (NULL == ci) {
+		DHD_ERROR(("%s: malloc failed!\n", __func__));
+		return -ENOMEM;
+	}
+
+	memset((unsigned char *)ci, 0, sizeof(struct chip_info));
+
+	/* bus/core/clk setup for register access */
+	/* Try forcing SDIO core to do ALPAvail request only */
+	clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ;
+	bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
+			clkset, &err);
+	if (err) {
+		DHD_ERROR(("%s: error writing for HT off\n", __func__));
+		goto fail;
+	}
+
+	/* If register supported, wait for ALPAvail and then force ALP */
+	/* This may take up to 15 milliseconds */
+	clkval = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
+			SBSDIO_FUNC1_CHIPCLKCSR, NULL);
+	if ((clkval & ~SBSDIO_AVBITS) == clkset) {
+		SPINWAIT(((clkval =
+				bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
+						SBSDIO_FUNC1_CHIPCLKCSR,
+						NULL)),
+				!SBSDIO_ALPAV(clkval)),
+				PMU_MAX_TRANSITION_DLY);
+		if (!SBSDIO_ALPAV(clkval)) {
+			DHD_ERROR(("%s: timeout on ALPAV wait, clkval 0x%02x\n",
+				__func__, clkval));
+			err = -EBUSY;
+			goto fail;
+		}
+		clkset = SBSDIO_FORCE_HW_CLKREQ_OFF |
+				SBSDIO_FORCE_ALP;
+		bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1,
+				SBSDIO_FUNC1_CHIPCLKCSR,
+				clkset, &err);
+		udelay(65);
+	} else {
+		DHD_ERROR(("%s: ChipClkCSR access: wrote 0x%02x read 0x%02x\n",
+			__func__, clkset, clkval));
+		err = -EACCES;
+		goto fail;
+	}
+
+	/* Also, disable the extra SDIO pull-ups */
+	bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SDIOPULLUP, 0,
+			 NULL);
+
+	err = dhdsdio_chip_recognition(bus->sdh, ci, regs);
+	if (err)
+		goto fail;
+
+	/*
+	 * Make sure any on-chip ARM is off (in case strapping is wrong),
+	 * or downloaded code was already running.
+	 */
+	dhdsdio_chip_disablecore(bus->sdh, ci->armcorebase);
+
+	bcmsdh_reg_write(bus->sdh,
+		CORE_CC_REG(ci->cccorebase, gpiopullup), 4, 0);
+	bcmsdh_reg_write(bus->sdh,
+		CORE_CC_REG(ci->cccorebase, gpiopulldown), 4, 0);
+
+	/* Disable F2 to clear any intermediate frame state on the dongle */
+	bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN,
+		SDIO_FUNC_ENABLE_1, NULL);
+
+	/* WAR: cmd52 backplane read so core HW will drop ALPReq */
+	clkval = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
+			0, NULL);
+
+	/* Done with backplane-dependent accesses, can drop clock... */
+	bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 0,
+			 NULL);
+
+	bus->ci = ci;
+	return 0;
+fail:
+	bus->ci = NULL;
+	kfree(ci);
+	return err;
+}
-- 
1.7.1


_______________________________________________
devel mailing list
devel@xxxxxxxxxxxxxxxxxxxxxx
http://driverdev.linuxdriverproject.org/mailman/listinfo/devel


[Index of Archives]     [Linux Driver Backports]     [DMA Engine]     [Linux GPIO]     [Linux SPI]     [Video for Linux]     [Linux USB Devel]     [Linux Coverity]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux