Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cb63e4c9 authored by Franky Lin's avatar Franky Lin Committed by Greg Kroah-Hartman
Browse files

staging: brcm80211: Add dhdsdio_chip_attach in dhd_sdio.c



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: default avatarFranky Lin <frankyl@broadcom.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent ddd0b091
Loading
Loading
Loading
Loading
+253 −0
Original line number Original line Diff line number Diff line
@@ -53,6 +53,7 @@
#include <dhdioctl.h>
#include <dhdioctl.h>
#include <sdiovar.h>
#include <sdiovar.h>
#include <siutils_priv.h>
#include <siutils_priv.h>
#include <bcmchip.h>


#ifndef DHDSDIO_MEM_DUMP_FNAME
#ifndef DHDSDIO_MEM_DUMP_FNAME
#define DHDSDIO_MEM_DUMP_FNAME         "mem_dump"
#define DHDSDIO_MEM_DUMP_FNAME         "mem_dump"
@@ -166,12 +167,28 @@ typedef struct dhd_console {
} dhd_console_t;
} dhd_console_t;
#endif				/* DHD_DEBUG */
#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 */
/* Private data for SDIO bus interaction */
typedef struct dhd_bus {
typedef struct dhd_bus {
	dhd_pub_t *dhd;
	dhd_pub_t *dhd;


	bcmsdh_info_t *sdh;	/* Handle for BCMSDH calls */
	bcmsdh_info_t *sdh;	/* Handle for BCMSDH calls */
	si_t *sih;		/* Handle for SI calls */
	si_t *sih;		/* Handle for SI calls */
	struct chip_info *ci;	/* Chip info struct */
	char *vars;		/* Variables (from CIS and/or other) */
	char *vars;		/* Variables (from CIS and/or other) */
	uint varsz;		/* Size of variables buffer */
	uint varsz;		/* Size of variables buffer */
	u32 sbaddr;		/* Current SB window pointer (-1, invalid) */
	u32 sbaddr;		/* Current SB window pointer (-1, invalid) */
@@ -465,6 +482,7 @@ static int dhdsdio_download_nvram(struct dhd_bus *bus);
#ifdef BCMEMBEDIMAGE
#ifdef BCMEMBEDIMAGE
static int dhdsdio_download_code_array(struct dhd_bus *bus);
static int dhdsdio_download_code_array(struct dhd_bus *bus);
#endif
#endif
static int dhdsdio_chip_attach(struct dhd_bus *bus, void *regs);


static void dhd_dongle_setmemsize(struct dhd_bus *bus, int mem_size)
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__));
		DHD_ERROR(("%s: si_attach failed!\n", __func__));
		goto fail;
		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);
	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;
	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;
}