105491d2cSKalle Valo /* 205491d2cSKalle Valo * Copyright (c) 2014 Broadcom Corporation 305491d2cSKalle Valo * 405491d2cSKalle Valo * Permission to use, copy, modify, and/or distribute this software for any 505491d2cSKalle Valo * purpose with or without fee is hereby granted, provided that the above 605491d2cSKalle Valo * copyright notice and this permission notice appear in all copies. 705491d2cSKalle Valo * 805491d2cSKalle Valo * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 905491d2cSKalle Valo * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1005491d2cSKalle Valo * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 1105491d2cSKalle Valo * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1205491d2cSKalle Valo * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 1305491d2cSKalle Valo * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 1405491d2cSKalle Valo * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1505491d2cSKalle Valo */ 1605491d2cSKalle Valo #include <linux/kernel.h> 1705491d2cSKalle Valo #include <linux/delay.h> 1805491d2cSKalle Valo #include <linux/list.h> 1905491d2cSKalle Valo #include <linux/ssb/ssb_regs.h> 2005491d2cSKalle Valo #include <linux/bcma/bcma.h> 2105491d2cSKalle Valo #include <linux/bcma/bcma_regs.h> 2205491d2cSKalle Valo 2305491d2cSKalle Valo #include <defs.h> 2405491d2cSKalle Valo #include <soc.h> 2505491d2cSKalle Valo #include <brcm_hw_ids.h> 2605491d2cSKalle Valo #include <brcmu_utils.h> 2705491d2cSKalle Valo #include <chipcommon.h> 2805491d2cSKalle Valo #include "debug.h" 2905491d2cSKalle Valo #include "chip.h" 3005491d2cSKalle Valo 3105491d2cSKalle Valo /* SOC Interconnect types (aka chip types) */ 3205491d2cSKalle Valo #define SOCI_SB 0 3305491d2cSKalle Valo #define SOCI_AI 1 3405491d2cSKalle Valo 3505491d2cSKalle Valo /* PL-368 DMP definitions */ 3605491d2cSKalle Valo #define DMP_DESC_TYPE_MSK 0x0000000F 3705491d2cSKalle Valo #define DMP_DESC_EMPTY 0x00000000 3805491d2cSKalle Valo #define DMP_DESC_VALID 0x00000001 3905491d2cSKalle Valo #define DMP_DESC_COMPONENT 0x00000001 4005491d2cSKalle Valo #define DMP_DESC_MASTER_PORT 0x00000003 4105491d2cSKalle Valo #define DMP_DESC_ADDRESS 0x00000005 4205491d2cSKalle Valo #define DMP_DESC_ADDRSIZE_GT32 0x00000008 4305491d2cSKalle Valo #define DMP_DESC_EOT 0x0000000F 4405491d2cSKalle Valo 4505491d2cSKalle Valo #define DMP_COMP_DESIGNER 0xFFF00000 4605491d2cSKalle Valo #define DMP_COMP_DESIGNER_S 20 4705491d2cSKalle Valo #define DMP_COMP_PARTNUM 0x000FFF00 4805491d2cSKalle Valo #define DMP_COMP_PARTNUM_S 8 4905491d2cSKalle Valo #define DMP_COMP_CLASS 0x000000F0 5005491d2cSKalle Valo #define DMP_COMP_CLASS_S 4 5105491d2cSKalle Valo #define DMP_COMP_REVISION 0xFF000000 5205491d2cSKalle Valo #define DMP_COMP_REVISION_S 24 5305491d2cSKalle Valo #define DMP_COMP_NUM_SWRAP 0x00F80000 5405491d2cSKalle Valo #define DMP_COMP_NUM_SWRAP_S 19 5505491d2cSKalle Valo #define DMP_COMP_NUM_MWRAP 0x0007C000 5605491d2cSKalle Valo #define DMP_COMP_NUM_MWRAP_S 14 5705491d2cSKalle Valo #define DMP_COMP_NUM_SPORT 0x00003E00 5805491d2cSKalle Valo #define DMP_COMP_NUM_SPORT_S 9 5905491d2cSKalle Valo #define DMP_COMP_NUM_MPORT 0x000001F0 6005491d2cSKalle Valo #define DMP_COMP_NUM_MPORT_S 4 6105491d2cSKalle Valo 6205491d2cSKalle Valo #define DMP_MASTER_PORT_UID 0x0000FF00 6305491d2cSKalle Valo #define DMP_MASTER_PORT_UID_S 8 6405491d2cSKalle Valo #define DMP_MASTER_PORT_NUM 0x000000F0 6505491d2cSKalle Valo #define DMP_MASTER_PORT_NUM_S 4 6605491d2cSKalle Valo 6705491d2cSKalle Valo #define DMP_SLAVE_ADDR_BASE 0xFFFFF000 6805491d2cSKalle Valo #define DMP_SLAVE_ADDR_BASE_S 12 6905491d2cSKalle Valo #define DMP_SLAVE_PORT_NUM 0x00000F00 7005491d2cSKalle Valo #define DMP_SLAVE_PORT_NUM_S 8 7105491d2cSKalle Valo #define DMP_SLAVE_TYPE 0x000000C0 7205491d2cSKalle Valo #define DMP_SLAVE_TYPE_S 6 7305491d2cSKalle Valo #define DMP_SLAVE_TYPE_SLAVE 0 7405491d2cSKalle Valo #define DMP_SLAVE_TYPE_BRIDGE 1 7505491d2cSKalle Valo #define DMP_SLAVE_TYPE_SWRAP 2 7605491d2cSKalle Valo #define DMP_SLAVE_TYPE_MWRAP 3 7705491d2cSKalle Valo #define DMP_SLAVE_SIZE_TYPE 0x00000030 7805491d2cSKalle Valo #define DMP_SLAVE_SIZE_TYPE_S 4 7905491d2cSKalle Valo #define DMP_SLAVE_SIZE_4K 0 8005491d2cSKalle Valo #define DMP_SLAVE_SIZE_8K 1 8105491d2cSKalle Valo #define DMP_SLAVE_SIZE_16K 2 8205491d2cSKalle Valo #define DMP_SLAVE_SIZE_DESC 3 8305491d2cSKalle Valo 8405491d2cSKalle Valo /* EROM CompIdentB */ 8505491d2cSKalle Valo #define CIB_REV_MASK 0xff000000 8605491d2cSKalle Valo #define CIB_REV_SHIFT 24 8705491d2cSKalle Valo 8805491d2cSKalle Valo /* ARM CR4 core specific control flag bits */ 8905491d2cSKalle Valo #define ARMCR4_BCMA_IOCTL_CPUHALT 0x0020 9005491d2cSKalle Valo 9105491d2cSKalle Valo /* D11 core specific control flag bits */ 9205491d2cSKalle Valo #define D11_BCMA_IOCTL_PHYCLOCKEN 0x0004 9305491d2cSKalle Valo #define D11_BCMA_IOCTL_PHYRESET 0x0008 9405491d2cSKalle Valo 9505491d2cSKalle Valo /* chip core base & ramsize */ 9605491d2cSKalle Valo /* bcm4329 */ 9705491d2cSKalle Valo /* SDIO device core, ID 0x829 */ 9805491d2cSKalle Valo #define BCM4329_CORE_BUS_BASE 0x18011000 9905491d2cSKalle Valo /* internal memory core, ID 0x80e */ 10005491d2cSKalle Valo #define BCM4329_CORE_SOCRAM_BASE 0x18003000 10105491d2cSKalle Valo /* ARM Cortex M3 core, ID 0x82a */ 10205491d2cSKalle Valo #define BCM4329_CORE_ARM_BASE 0x18002000 10305491d2cSKalle Valo 10405491d2cSKalle Valo /* Max possibly supported memory size (limited by IO mapped memory) */ 10505491d2cSKalle Valo #define BRCMF_CHIP_MAX_MEMSIZE (4 * 1024 * 1024) 10605491d2cSKalle Valo 10705491d2cSKalle Valo #define CORE_SB(base, field) \ 10805491d2cSKalle Valo (base + SBCONFIGOFF + offsetof(struct sbconfig, field)) 10905491d2cSKalle Valo #define SBCOREREV(sbidh) \ 11005491d2cSKalle Valo ((((sbidh) & SSB_IDHIGH_RCHI) >> SSB_IDHIGH_RCHI_SHIFT) | \ 11105491d2cSKalle Valo ((sbidh) & SSB_IDHIGH_RCLO)) 11205491d2cSKalle Valo 11305491d2cSKalle Valo struct sbconfig { 11405491d2cSKalle Valo u32 PAD[2]; 11505491d2cSKalle Valo u32 sbipsflag; /* initiator port ocp slave flag */ 11605491d2cSKalle Valo u32 PAD[3]; 11705491d2cSKalle Valo u32 sbtpsflag; /* target port ocp slave flag */ 11805491d2cSKalle Valo u32 PAD[11]; 11905491d2cSKalle Valo u32 sbtmerrloga; /* (sonics >= 2.3) */ 12005491d2cSKalle Valo u32 PAD; 12105491d2cSKalle Valo u32 sbtmerrlog; /* (sonics >= 2.3) */ 12205491d2cSKalle Valo u32 PAD[3]; 12305491d2cSKalle Valo u32 sbadmatch3; /* address match3 */ 12405491d2cSKalle Valo u32 PAD; 12505491d2cSKalle Valo u32 sbadmatch2; /* address match2 */ 12605491d2cSKalle Valo u32 PAD; 12705491d2cSKalle Valo u32 sbadmatch1; /* address match1 */ 12805491d2cSKalle Valo u32 PAD[7]; 12905491d2cSKalle Valo u32 sbimstate; /* initiator agent state */ 13005491d2cSKalle Valo u32 sbintvec; /* interrupt mask */ 13105491d2cSKalle Valo u32 sbtmstatelow; /* target state */ 13205491d2cSKalle Valo u32 sbtmstatehigh; /* target state */ 13305491d2cSKalle Valo u32 sbbwa0; /* bandwidth allocation table0 */ 13405491d2cSKalle Valo u32 PAD; 13505491d2cSKalle Valo u32 sbimconfiglow; /* initiator configuration */ 13605491d2cSKalle Valo u32 sbimconfighigh; /* initiator configuration */ 13705491d2cSKalle Valo u32 sbadmatch0; /* address match0 */ 13805491d2cSKalle Valo u32 PAD; 13905491d2cSKalle Valo u32 sbtmconfiglow; /* target configuration */ 14005491d2cSKalle Valo u32 sbtmconfighigh; /* target configuration */ 14105491d2cSKalle Valo u32 sbbconfig; /* broadcast configuration */ 14205491d2cSKalle Valo u32 PAD; 14305491d2cSKalle Valo u32 sbbstate; /* broadcast state */ 14405491d2cSKalle Valo u32 PAD[3]; 14505491d2cSKalle Valo u32 sbactcnfg; /* activate configuration */ 14605491d2cSKalle Valo u32 PAD[3]; 14705491d2cSKalle Valo u32 sbflagst; /* current sbflags */ 14805491d2cSKalle Valo u32 PAD[3]; 14905491d2cSKalle Valo u32 sbidlow; /* identification */ 15005491d2cSKalle Valo u32 sbidhigh; /* identification */ 15105491d2cSKalle Valo }; 15205491d2cSKalle Valo 15305491d2cSKalle Valo /* bankidx and bankinfo reg defines corerev >= 8 */ 15405491d2cSKalle Valo #define SOCRAM_BANKINFO_RETNTRAM_MASK 0x00010000 15505491d2cSKalle Valo #define SOCRAM_BANKINFO_SZMASK 0x0000007f 15605491d2cSKalle Valo #define SOCRAM_BANKIDX_ROM_MASK 0x00000100 15705491d2cSKalle Valo 15805491d2cSKalle Valo #define SOCRAM_BANKIDX_MEMTYPE_SHIFT 8 15905491d2cSKalle Valo /* socram bankinfo memtype */ 16005491d2cSKalle Valo #define SOCRAM_MEMTYPE_RAM 0 16105491d2cSKalle Valo #define SOCRAM_MEMTYPE_R0M 1 16205491d2cSKalle Valo #define SOCRAM_MEMTYPE_DEVRAM 2 16305491d2cSKalle Valo 16405491d2cSKalle Valo #define SOCRAM_BANKINFO_SZBASE 8192 16505491d2cSKalle Valo #define SRCI_LSS_MASK 0x00f00000 16605491d2cSKalle Valo #define SRCI_LSS_SHIFT 20 16705491d2cSKalle Valo #define SRCI_SRNB_MASK 0xf0 16805491d2cSKalle Valo #define SRCI_SRNB_SHIFT 4 16905491d2cSKalle Valo #define SRCI_SRBSZ_MASK 0xf 17005491d2cSKalle Valo #define SRCI_SRBSZ_SHIFT 0 17105491d2cSKalle Valo #define SR_BSZ_BASE 14 17205491d2cSKalle Valo 17305491d2cSKalle Valo struct sbsocramregs { 17405491d2cSKalle Valo u32 coreinfo; 17505491d2cSKalle Valo u32 bwalloc; 17605491d2cSKalle Valo u32 extracoreinfo; 17705491d2cSKalle Valo u32 biststat; 17805491d2cSKalle Valo u32 bankidx; 17905491d2cSKalle Valo u32 standbyctrl; 18005491d2cSKalle Valo 18105491d2cSKalle Valo u32 errlogstatus; /* rev 6 */ 18205491d2cSKalle Valo u32 errlogaddr; /* rev 6 */ 18305491d2cSKalle Valo /* used for patching rev 3 & 5 */ 18405491d2cSKalle Valo u32 cambankidx; 18505491d2cSKalle Valo u32 cambankstandbyctrl; 18605491d2cSKalle Valo u32 cambankpatchctrl; 18705491d2cSKalle Valo u32 cambankpatchtblbaseaddr; 18805491d2cSKalle Valo u32 cambankcmdreg; 18905491d2cSKalle Valo u32 cambankdatareg; 19005491d2cSKalle Valo u32 cambankmaskreg; 19105491d2cSKalle Valo u32 PAD[1]; 19205491d2cSKalle Valo u32 bankinfo; /* corev 8 */ 19305491d2cSKalle Valo u32 bankpda; 19405491d2cSKalle Valo u32 PAD[14]; 19505491d2cSKalle Valo u32 extmemconfig; 19605491d2cSKalle Valo u32 extmemparitycsr; 19705491d2cSKalle Valo u32 extmemparityerrdata; 19805491d2cSKalle Valo u32 extmemparityerrcnt; 19905491d2cSKalle Valo u32 extmemwrctrlandsize; 20005491d2cSKalle Valo u32 PAD[84]; 20105491d2cSKalle Valo u32 workaround; 20205491d2cSKalle Valo u32 pwrctl; /* corerev >= 2 */ 20305491d2cSKalle Valo u32 PAD[133]; 20405491d2cSKalle Valo u32 sr_control; /* corerev >= 15 */ 20505491d2cSKalle Valo u32 sr_status; /* corerev >= 15 */ 20605491d2cSKalle Valo u32 sr_address; /* corerev >= 15 */ 20705491d2cSKalle Valo u32 sr_data; /* corerev >= 15 */ 20805491d2cSKalle Valo }; 20905491d2cSKalle Valo 21005491d2cSKalle Valo #define SOCRAMREGOFFS(_f) offsetof(struct sbsocramregs, _f) 21105491d2cSKalle Valo #define SYSMEMREGOFFS(_f) offsetof(struct sbsocramregs, _f) 21205491d2cSKalle Valo 21305491d2cSKalle Valo #define ARMCR4_CAP (0x04) 21405491d2cSKalle Valo #define ARMCR4_BANKIDX (0x40) 21505491d2cSKalle Valo #define ARMCR4_BANKINFO (0x44) 21605491d2cSKalle Valo #define ARMCR4_BANKPDA (0x4C) 21705491d2cSKalle Valo 21805491d2cSKalle Valo #define ARMCR4_TCBBNB_MASK 0xf0 21905491d2cSKalle Valo #define ARMCR4_TCBBNB_SHIFT 4 22005491d2cSKalle Valo #define ARMCR4_TCBANB_MASK 0xf 22105491d2cSKalle Valo #define ARMCR4_TCBANB_SHIFT 0 22205491d2cSKalle Valo 22305491d2cSKalle Valo #define ARMCR4_BSZ_MASK 0x3f 22405491d2cSKalle Valo #define ARMCR4_BSZ_MULT 8192 22505491d2cSKalle Valo 22605491d2cSKalle Valo struct brcmf_core_priv { 22705491d2cSKalle Valo struct brcmf_core pub; 22805491d2cSKalle Valo u32 wrapbase; 22905491d2cSKalle Valo struct list_head list; 23005491d2cSKalle Valo struct brcmf_chip_priv *chip; 23105491d2cSKalle Valo }; 23205491d2cSKalle Valo 23305491d2cSKalle Valo struct brcmf_chip_priv { 23405491d2cSKalle Valo struct brcmf_chip pub; 23505491d2cSKalle Valo const struct brcmf_buscore_ops *ops; 23605491d2cSKalle Valo void *ctx; 23705491d2cSKalle Valo /* assured first core is chipcommon, second core is buscore */ 23805491d2cSKalle Valo struct list_head cores; 23905491d2cSKalle Valo u16 num_cores; 24005491d2cSKalle Valo 24105491d2cSKalle Valo bool (*iscoreup)(struct brcmf_core_priv *core); 24205491d2cSKalle Valo void (*coredisable)(struct brcmf_core_priv *core, u32 prereset, 24305491d2cSKalle Valo u32 reset); 24405491d2cSKalle Valo void (*resetcore)(struct brcmf_core_priv *core, u32 prereset, u32 reset, 24505491d2cSKalle Valo u32 postreset); 24605491d2cSKalle Valo }; 24705491d2cSKalle Valo 24805491d2cSKalle Valo static void brcmf_chip_sb_corerev(struct brcmf_chip_priv *ci, 24905491d2cSKalle Valo struct brcmf_core *core) 25005491d2cSKalle Valo { 25105491d2cSKalle Valo u32 regdata; 25205491d2cSKalle Valo 25305491d2cSKalle Valo regdata = ci->ops->read32(ci->ctx, CORE_SB(core->base, sbidhigh)); 25405491d2cSKalle Valo core->rev = SBCOREREV(regdata); 25505491d2cSKalle Valo } 25605491d2cSKalle Valo 25705491d2cSKalle Valo static bool brcmf_chip_sb_iscoreup(struct brcmf_core_priv *core) 25805491d2cSKalle Valo { 25905491d2cSKalle Valo struct brcmf_chip_priv *ci; 26005491d2cSKalle Valo u32 regdata; 26105491d2cSKalle Valo u32 address; 26205491d2cSKalle Valo 26305491d2cSKalle Valo ci = core->chip; 26405491d2cSKalle Valo address = CORE_SB(core->pub.base, sbtmstatelow); 26505491d2cSKalle Valo regdata = ci->ops->read32(ci->ctx, address); 26605491d2cSKalle Valo regdata &= (SSB_TMSLOW_RESET | SSB_TMSLOW_REJECT | 26705491d2cSKalle Valo SSB_IMSTATE_REJECT | SSB_TMSLOW_CLOCK); 26805491d2cSKalle Valo return SSB_TMSLOW_CLOCK == regdata; 26905491d2cSKalle Valo } 27005491d2cSKalle Valo 27105491d2cSKalle Valo static bool brcmf_chip_ai_iscoreup(struct brcmf_core_priv *core) 27205491d2cSKalle Valo { 27305491d2cSKalle Valo struct brcmf_chip_priv *ci; 27405491d2cSKalle Valo u32 regdata; 27505491d2cSKalle Valo bool ret; 27605491d2cSKalle Valo 27705491d2cSKalle Valo ci = core->chip; 27805491d2cSKalle Valo regdata = ci->ops->read32(ci->ctx, core->wrapbase + BCMA_IOCTL); 27905491d2cSKalle Valo ret = (regdata & (BCMA_IOCTL_FGC | BCMA_IOCTL_CLK)) == BCMA_IOCTL_CLK; 28005491d2cSKalle Valo 28105491d2cSKalle Valo regdata = ci->ops->read32(ci->ctx, core->wrapbase + BCMA_RESET_CTL); 28205491d2cSKalle Valo ret = ret && ((regdata & BCMA_RESET_CTL_RESET) == 0); 28305491d2cSKalle Valo 28405491d2cSKalle Valo return ret; 28505491d2cSKalle Valo } 28605491d2cSKalle Valo 28705491d2cSKalle Valo static void brcmf_chip_sb_coredisable(struct brcmf_core_priv *core, 28805491d2cSKalle Valo u32 prereset, u32 reset) 28905491d2cSKalle Valo { 29005491d2cSKalle Valo struct brcmf_chip_priv *ci; 29105491d2cSKalle Valo u32 val, base; 29205491d2cSKalle Valo 29305491d2cSKalle Valo ci = core->chip; 29405491d2cSKalle Valo base = core->pub.base; 29505491d2cSKalle Valo val = ci->ops->read32(ci->ctx, CORE_SB(base, sbtmstatelow)); 29605491d2cSKalle Valo if (val & SSB_TMSLOW_RESET) 29705491d2cSKalle Valo return; 29805491d2cSKalle Valo 29905491d2cSKalle Valo val = ci->ops->read32(ci->ctx, CORE_SB(base, sbtmstatelow)); 30005491d2cSKalle Valo if ((val & SSB_TMSLOW_CLOCK) != 0) { 30105491d2cSKalle Valo /* 30205491d2cSKalle Valo * set target reject and spin until busy is clear 30305491d2cSKalle Valo * (preserve core-specific bits) 30405491d2cSKalle Valo */ 30505491d2cSKalle Valo val = ci->ops->read32(ci->ctx, CORE_SB(base, sbtmstatelow)); 30605491d2cSKalle Valo ci->ops->write32(ci->ctx, CORE_SB(base, sbtmstatelow), 30705491d2cSKalle Valo val | SSB_TMSLOW_REJECT); 30805491d2cSKalle Valo 30905491d2cSKalle Valo val = ci->ops->read32(ci->ctx, CORE_SB(base, sbtmstatelow)); 31005491d2cSKalle Valo udelay(1); 31105491d2cSKalle Valo SPINWAIT((ci->ops->read32(ci->ctx, CORE_SB(base, sbtmstatehigh)) 31205491d2cSKalle Valo & SSB_TMSHIGH_BUSY), 100000); 31305491d2cSKalle Valo 31405491d2cSKalle Valo val = ci->ops->read32(ci->ctx, CORE_SB(base, sbtmstatehigh)); 31505491d2cSKalle Valo if (val & SSB_TMSHIGH_BUSY) 31605491d2cSKalle Valo brcmf_err("core state still busy\n"); 31705491d2cSKalle Valo 31805491d2cSKalle Valo val = ci->ops->read32(ci->ctx, CORE_SB(base, sbidlow)); 31905491d2cSKalle Valo if (val & SSB_IDLOW_INITIATOR) { 32005491d2cSKalle Valo val = ci->ops->read32(ci->ctx, 32105491d2cSKalle Valo CORE_SB(base, sbimstate)); 32205491d2cSKalle Valo val |= SSB_IMSTATE_REJECT; 32305491d2cSKalle Valo ci->ops->write32(ci->ctx, 32405491d2cSKalle Valo CORE_SB(base, sbimstate), val); 32505491d2cSKalle Valo val = ci->ops->read32(ci->ctx, 32605491d2cSKalle Valo CORE_SB(base, sbimstate)); 32705491d2cSKalle Valo udelay(1); 32805491d2cSKalle Valo SPINWAIT((ci->ops->read32(ci->ctx, 32905491d2cSKalle Valo CORE_SB(base, sbimstate)) & 33005491d2cSKalle Valo SSB_IMSTATE_BUSY), 100000); 33105491d2cSKalle Valo } 33205491d2cSKalle Valo 33305491d2cSKalle Valo /* set reset and reject while enabling the clocks */ 33405491d2cSKalle Valo val = SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK | 33505491d2cSKalle Valo SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET; 33605491d2cSKalle Valo ci->ops->write32(ci->ctx, CORE_SB(base, sbtmstatelow), val); 33705491d2cSKalle Valo val = ci->ops->read32(ci->ctx, CORE_SB(base, sbtmstatelow)); 33805491d2cSKalle Valo udelay(10); 33905491d2cSKalle Valo 34005491d2cSKalle Valo /* clear the initiator reject bit */ 34105491d2cSKalle Valo val = ci->ops->read32(ci->ctx, CORE_SB(base, sbidlow)); 34205491d2cSKalle Valo if (val & SSB_IDLOW_INITIATOR) { 34305491d2cSKalle Valo val = ci->ops->read32(ci->ctx, 34405491d2cSKalle Valo CORE_SB(base, sbimstate)); 34505491d2cSKalle Valo val &= ~SSB_IMSTATE_REJECT; 34605491d2cSKalle Valo ci->ops->write32(ci->ctx, 34705491d2cSKalle Valo CORE_SB(base, sbimstate), val); 34805491d2cSKalle Valo } 34905491d2cSKalle Valo } 35005491d2cSKalle Valo 35105491d2cSKalle Valo /* leave reset and reject asserted */ 35205491d2cSKalle Valo ci->ops->write32(ci->ctx, CORE_SB(base, sbtmstatelow), 35305491d2cSKalle Valo (SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET)); 35405491d2cSKalle Valo udelay(1); 35505491d2cSKalle Valo } 35605491d2cSKalle Valo 35705491d2cSKalle Valo static void brcmf_chip_ai_coredisable(struct brcmf_core_priv *core, 35805491d2cSKalle Valo u32 prereset, u32 reset) 35905491d2cSKalle Valo { 36005491d2cSKalle Valo struct brcmf_chip_priv *ci; 36105491d2cSKalle Valo u32 regdata; 36205491d2cSKalle Valo 36305491d2cSKalle Valo ci = core->chip; 36405491d2cSKalle Valo 36505491d2cSKalle Valo /* if core is already in reset, skip reset */ 36605491d2cSKalle Valo regdata = ci->ops->read32(ci->ctx, core->wrapbase + BCMA_RESET_CTL); 36705491d2cSKalle Valo if ((regdata & BCMA_RESET_CTL_RESET) != 0) 36805491d2cSKalle Valo goto in_reset_configure; 36905491d2cSKalle Valo 37005491d2cSKalle Valo /* configure reset */ 37105491d2cSKalle Valo ci->ops->write32(ci->ctx, core->wrapbase + BCMA_IOCTL, 37205491d2cSKalle Valo prereset | BCMA_IOCTL_FGC | BCMA_IOCTL_CLK); 37305491d2cSKalle Valo ci->ops->read32(ci->ctx, core->wrapbase + BCMA_IOCTL); 37405491d2cSKalle Valo 37505491d2cSKalle Valo /* put in reset */ 37605491d2cSKalle Valo ci->ops->write32(ci->ctx, core->wrapbase + BCMA_RESET_CTL, 37705491d2cSKalle Valo BCMA_RESET_CTL_RESET); 37805491d2cSKalle Valo usleep_range(10, 20); 37905491d2cSKalle Valo 38005491d2cSKalle Valo /* wait till reset is 1 */ 38105491d2cSKalle Valo SPINWAIT(ci->ops->read32(ci->ctx, core->wrapbase + BCMA_RESET_CTL) != 38205491d2cSKalle Valo BCMA_RESET_CTL_RESET, 300); 38305491d2cSKalle Valo 38405491d2cSKalle Valo in_reset_configure: 38505491d2cSKalle Valo /* in-reset configure */ 38605491d2cSKalle Valo ci->ops->write32(ci->ctx, core->wrapbase + BCMA_IOCTL, 38705491d2cSKalle Valo reset | BCMA_IOCTL_FGC | BCMA_IOCTL_CLK); 38805491d2cSKalle Valo ci->ops->read32(ci->ctx, core->wrapbase + BCMA_IOCTL); 38905491d2cSKalle Valo } 39005491d2cSKalle Valo 39105491d2cSKalle Valo static void brcmf_chip_sb_resetcore(struct brcmf_core_priv *core, u32 prereset, 39205491d2cSKalle Valo u32 reset, u32 postreset) 39305491d2cSKalle Valo { 39405491d2cSKalle Valo struct brcmf_chip_priv *ci; 39505491d2cSKalle Valo u32 regdata; 39605491d2cSKalle Valo u32 base; 39705491d2cSKalle Valo 39805491d2cSKalle Valo ci = core->chip; 39905491d2cSKalle Valo base = core->pub.base; 40005491d2cSKalle Valo /* 40105491d2cSKalle Valo * Must do the disable sequence first to work for 40205491d2cSKalle Valo * arbitrary current core state. 40305491d2cSKalle Valo */ 40405491d2cSKalle Valo brcmf_chip_sb_coredisable(core, 0, 0); 40505491d2cSKalle Valo 40605491d2cSKalle Valo /* 40705491d2cSKalle Valo * Now do the initialization sequence. 40805491d2cSKalle Valo * set reset while enabling the clock and 40905491d2cSKalle Valo * forcing them on throughout the core 41005491d2cSKalle Valo */ 41105491d2cSKalle Valo ci->ops->write32(ci->ctx, CORE_SB(base, sbtmstatelow), 41205491d2cSKalle Valo SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK | 41305491d2cSKalle Valo SSB_TMSLOW_RESET); 41405491d2cSKalle Valo regdata = ci->ops->read32(ci->ctx, CORE_SB(base, sbtmstatelow)); 41505491d2cSKalle Valo udelay(1); 41605491d2cSKalle Valo 41705491d2cSKalle Valo /* clear any serror */ 41805491d2cSKalle Valo regdata = ci->ops->read32(ci->ctx, CORE_SB(base, sbtmstatehigh)); 41905491d2cSKalle Valo if (regdata & SSB_TMSHIGH_SERR) 42005491d2cSKalle Valo ci->ops->write32(ci->ctx, CORE_SB(base, sbtmstatehigh), 0); 42105491d2cSKalle Valo 42205491d2cSKalle Valo regdata = ci->ops->read32(ci->ctx, CORE_SB(base, sbimstate)); 42305491d2cSKalle Valo if (regdata & (SSB_IMSTATE_IBE | SSB_IMSTATE_TO)) { 42405491d2cSKalle Valo regdata &= ~(SSB_IMSTATE_IBE | SSB_IMSTATE_TO); 42505491d2cSKalle Valo ci->ops->write32(ci->ctx, CORE_SB(base, sbimstate), regdata); 42605491d2cSKalle Valo } 42705491d2cSKalle Valo 42805491d2cSKalle Valo /* clear reset and allow it to propagate throughout the core */ 42905491d2cSKalle Valo ci->ops->write32(ci->ctx, CORE_SB(base, sbtmstatelow), 43005491d2cSKalle Valo SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK); 43105491d2cSKalle Valo regdata = ci->ops->read32(ci->ctx, CORE_SB(base, sbtmstatelow)); 43205491d2cSKalle Valo udelay(1); 43305491d2cSKalle Valo 43405491d2cSKalle Valo /* leave clock enabled */ 43505491d2cSKalle Valo ci->ops->write32(ci->ctx, CORE_SB(base, sbtmstatelow), 43605491d2cSKalle Valo SSB_TMSLOW_CLOCK); 43705491d2cSKalle Valo regdata = ci->ops->read32(ci->ctx, CORE_SB(base, sbtmstatelow)); 43805491d2cSKalle Valo udelay(1); 43905491d2cSKalle Valo } 44005491d2cSKalle Valo 44105491d2cSKalle Valo static void brcmf_chip_ai_resetcore(struct brcmf_core_priv *core, u32 prereset, 44205491d2cSKalle Valo u32 reset, u32 postreset) 44305491d2cSKalle Valo { 44405491d2cSKalle Valo struct brcmf_chip_priv *ci; 44505491d2cSKalle Valo int count; 44605491d2cSKalle Valo 44705491d2cSKalle Valo ci = core->chip; 44805491d2cSKalle Valo 44905491d2cSKalle Valo /* must disable first to work for arbitrary current core state */ 45005491d2cSKalle Valo brcmf_chip_ai_coredisable(core, prereset, reset); 45105491d2cSKalle Valo 45205491d2cSKalle Valo count = 0; 45305491d2cSKalle Valo while (ci->ops->read32(ci->ctx, core->wrapbase + BCMA_RESET_CTL) & 45405491d2cSKalle Valo BCMA_RESET_CTL_RESET) { 45505491d2cSKalle Valo ci->ops->write32(ci->ctx, core->wrapbase + BCMA_RESET_CTL, 0); 45605491d2cSKalle Valo count++; 45705491d2cSKalle Valo if (count > 50) 45805491d2cSKalle Valo break; 45905491d2cSKalle Valo usleep_range(40, 60); 46005491d2cSKalle Valo } 46105491d2cSKalle Valo 46205491d2cSKalle Valo ci->ops->write32(ci->ctx, core->wrapbase + BCMA_IOCTL, 46305491d2cSKalle Valo postreset | BCMA_IOCTL_CLK); 46405491d2cSKalle Valo ci->ops->read32(ci->ctx, core->wrapbase + BCMA_IOCTL); 46505491d2cSKalle Valo } 46605491d2cSKalle Valo 46705491d2cSKalle Valo static char *brcmf_chip_name(uint chipid, char *buf, uint len) 46805491d2cSKalle Valo { 46905491d2cSKalle Valo const char *fmt; 47005491d2cSKalle Valo 47105491d2cSKalle Valo fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x"; 47205491d2cSKalle Valo snprintf(buf, len, fmt, chipid); 47305491d2cSKalle Valo return buf; 47405491d2cSKalle Valo } 47505491d2cSKalle Valo 47605491d2cSKalle Valo static struct brcmf_core *brcmf_chip_add_core(struct brcmf_chip_priv *ci, 47705491d2cSKalle Valo u16 coreid, u32 base, 47805491d2cSKalle Valo u32 wrapbase) 47905491d2cSKalle Valo { 48005491d2cSKalle Valo struct brcmf_core_priv *core; 48105491d2cSKalle Valo 48205491d2cSKalle Valo core = kzalloc(sizeof(*core), GFP_KERNEL); 48305491d2cSKalle Valo if (!core) 48405491d2cSKalle Valo return ERR_PTR(-ENOMEM); 48505491d2cSKalle Valo 48605491d2cSKalle Valo core->pub.id = coreid; 48705491d2cSKalle Valo core->pub.base = base; 48805491d2cSKalle Valo core->chip = ci; 48905491d2cSKalle Valo core->wrapbase = wrapbase; 49005491d2cSKalle Valo 49105491d2cSKalle Valo list_add_tail(&core->list, &ci->cores); 49205491d2cSKalle Valo return &core->pub; 49305491d2cSKalle Valo } 49405491d2cSKalle Valo 49505491d2cSKalle Valo /* safety check for chipinfo */ 49605491d2cSKalle Valo static int brcmf_chip_cores_check(struct brcmf_chip_priv *ci) 49705491d2cSKalle Valo { 49805491d2cSKalle Valo struct brcmf_core_priv *core; 49905491d2cSKalle Valo bool need_socram = false; 50005491d2cSKalle Valo bool has_socram = false; 50105491d2cSKalle Valo bool cpu_found = false; 50205491d2cSKalle Valo int idx = 1; 50305491d2cSKalle Valo 50405491d2cSKalle Valo list_for_each_entry(core, &ci->cores, list) { 50505491d2cSKalle Valo brcmf_dbg(INFO, " [%-2d] core 0x%x:%-2d base 0x%08x wrap 0x%08x\n", 50605491d2cSKalle Valo idx++, core->pub.id, core->pub.rev, core->pub.base, 50705491d2cSKalle Valo core->wrapbase); 50805491d2cSKalle Valo 50905491d2cSKalle Valo switch (core->pub.id) { 51005491d2cSKalle Valo case BCMA_CORE_ARM_CM3: 51105491d2cSKalle Valo cpu_found = true; 51205491d2cSKalle Valo need_socram = true; 51305491d2cSKalle Valo break; 51405491d2cSKalle Valo case BCMA_CORE_INTERNAL_MEM: 51505491d2cSKalle Valo has_socram = true; 51605491d2cSKalle Valo break; 51705491d2cSKalle Valo case BCMA_CORE_ARM_CR4: 51805491d2cSKalle Valo cpu_found = true; 51905491d2cSKalle Valo break; 52005491d2cSKalle Valo case BCMA_CORE_ARM_CA7: 52105491d2cSKalle Valo cpu_found = true; 52205491d2cSKalle Valo break; 52305491d2cSKalle Valo default: 52405491d2cSKalle Valo break; 52505491d2cSKalle Valo } 52605491d2cSKalle Valo } 52705491d2cSKalle Valo 52805491d2cSKalle Valo if (!cpu_found) { 52905491d2cSKalle Valo brcmf_err("CPU core not detected\n"); 53005491d2cSKalle Valo return -ENXIO; 53105491d2cSKalle Valo } 53205491d2cSKalle Valo /* check RAM core presence for ARM CM3 core */ 53305491d2cSKalle Valo if (need_socram && !has_socram) { 53405491d2cSKalle Valo brcmf_err("RAM core not provided with ARM CM3 core\n"); 53505491d2cSKalle Valo return -ENODEV; 53605491d2cSKalle Valo } 53705491d2cSKalle Valo return 0; 53805491d2cSKalle Valo } 53905491d2cSKalle Valo 54005491d2cSKalle Valo static u32 brcmf_chip_core_read32(struct brcmf_core_priv *core, u16 reg) 54105491d2cSKalle Valo { 54205491d2cSKalle Valo return core->chip->ops->read32(core->chip->ctx, core->pub.base + reg); 54305491d2cSKalle Valo } 54405491d2cSKalle Valo 54505491d2cSKalle Valo static void brcmf_chip_core_write32(struct brcmf_core_priv *core, 54605491d2cSKalle Valo u16 reg, u32 val) 54705491d2cSKalle Valo { 54805491d2cSKalle Valo core->chip->ops->write32(core->chip->ctx, core->pub.base + reg, val); 54905491d2cSKalle Valo } 55005491d2cSKalle Valo 55105491d2cSKalle Valo static bool brcmf_chip_socram_banksize(struct brcmf_core_priv *core, u8 idx, 55205491d2cSKalle Valo u32 *banksize) 55305491d2cSKalle Valo { 55405491d2cSKalle Valo u32 bankinfo; 55505491d2cSKalle Valo u32 bankidx = (SOCRAM_MEMTYPE_RAM << SOCRAM_BANKIDX_MEMTYPE_SHIFT); 55605491d2cSKalle Valo 55705491d2cSKalle Valo bankidx |= idx; 55805491d2cSKalle Valo brcmf_chip_core_write32(core, SOCRAMREGOFFS(bankidx), bankidx); 55905491d2cSKalle Valo bankinfo = brcmf_chip_core_read32(core, SOCRAMREGOFFS(bankinfo)); 56005491d2cSKalle Valo *banksize = (bankinfo & SOCRAM_BANKINFO_SZMASK) + 1; 56105491d2cSKalle Valo *banksize *= SOCRAM_BANKINFO_SZBASE; 56205491d2cSKalle Valo return !!(bankinfo & SOCRAM_BANKINFO_RETNTRAM_MASK); 56305491d2cSKalle Valo } 56405491d2cSKalle Valo 56505491d2cSKalle Valo static void brcmf_chip_socram_ramsize(struct brcmf_core_priv *sr, u32 *ramsize, 56605491d2cSKalle Valo u32 *srsize) 56705491d2cSKalle Valo { 56805491d2cSKalle Valo u32 coreinfo; 56905491d2cSKalle Valo uint nb, banksize, lss; 57005491d2cSKalle Valo bool retent; 57105491d2cSKalle Valo int i; 57205491d2cSKalle Valo 57305491d2cSKalle Valo *ramsize = 0; 57405491d2cSKalle Valo *srsize = 0; 57505491d2cSKalle Valo 57605491d2cSKalle Valo if (WARN_ON(sr->pub.rev < 4)) 57705491d2cSKalle Valo return; 57805491d2cSKalle Valo 57905491d2cSKalle Valo if (!brcmf_chip_iscoreup(&sr->pub)) 58005491d2cSKalle Valo brcmf_chip_resetcore(&sr->pub, 0, 0, 0); 58105491d2cSKalle Valo 58205491d2cSKalle Valo /* Get info for determining size */ 58305491d2cSKalle Valo coreinfo = brcmf_chip_core_read32(sr, SOCRAMREGOFFS(coreinfo)); 58405491d2cSKalle Valo nb = (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT; 58505491d2cSKalle Valo 58605491d2cSKalle Valo if ((sr->pub.rev <= 7) || (sr->pub.rev == 12)) { 58705491d2cSKalle Valo banksize = (coreinfo & SRCI_SRBSZ_MASK); 58805491d2cSKalle Valo lss = (coreinfo & SRCI_LSS_MASK) >> SRCI_LSS_SHIFT; 58905491d2cSKalle Valo if (lss != 0) 59005491d2cSKalle Valo nb--; 59105491d2cSKalle Valo *ramsize = nb * (1 << (banksize + SR_BSZ_BASE)); 59205491d2cSKalle Valo if (lss != 0) 59305491d2cSKalle Valo *ramsize += (1 << ((lss - 1) + SR_BSZ_BASE)); 59405491d2cSKalle Valo } else { 59505491d2cSKalle Valo nb = (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT; 59605491d2cSKalle Valo for (i = 0; i < nb; i++) { 59705491d2cSKalle Valo retent = brcmf_chip_socram_banksize(sr, i, &banksize); 59805491d2cSKalle Valo *ramsize += banksize; 59905491d2cSKalle Valo if (retent) 60005491d2cSKalle Valo *srsize += banksize; 60105491d2cSKalle Valo } 60205491d2cSKalle Valo } 60305491d2cSKalle Valo 60405491d2cSKalle Valo /* hardcoded save&restore memory sizes */ 60505491d2cSKalle Valo switch (sr->chip->pub.chip) { 60605491d2cSKalle Valo case BRCM_CC_4334_CHIP_ID: 60705491d2cSKalle Valo if (sr->chip->pub.chiprev < 2) 60805491d2cSKalle Valo *srsize = (32 * 1024); 60905491d2cSKalle Valo break; 61005491d2cSKalle Valo case BRCM_CC_43430_CHIP_ID: 61105491d2cSKalle Valo /* assume sr for now as we can not check 61205491d2cSKalle Valo * firmware sr capability at this point. 61305491d2cSKalle Valo */ 61405491d2cSKalle Valo *srsize = (64 * 1024); 61505491d2cSKalle Valo break; 61605491d2cSKalle Valo default: 61705491d2cSKalle Valo break; 61805491d2cSKalle Valo } 61905491d2cSKalle Valo } 62005491d2cSKalle Valo 62105491d2cSKalle Valo /** Return the SYS MEM size */ 62205491d2cSKalle Valo static u32 brcmf_chip_sysmem_ramsize(struct brcmf_core_priv *sysmem) 62305491d2cSKalle Valo { 62405491d2cSKalle Valo u32 memsize = 0; 62505491d2cSKalle Valo u32 coreinfo; 62605491d2cSKalle Valo u32 idx; 62705491d2cSKalle Valo u32 nb; 62805491d2cSKalle Valo u32 banksize; 62905491d2cSKalle Valo 63005491d2cSKalle Valo if (!brcmf_chip_iscoreup(&sysmem->pub)) 63105491d2cSKalle Valo brcmf_chip_resetcore(&sysmem->pub, 0, 0, 0); 63205491d2cSKalle Valo 63305491d2cSKalle Valo coreinfo = brcmf_chip_core_read32(sysmem, SYSMEMREGOFFS(coreinfo)); 63405491d2cSKalle Valo nb = (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT; 63505491d2cSKalle Valo 63605491d2cSKalle Valo for (idx = 0; idx < nb; idx++) { 63705491d2cSKalle Valo brcmf_chip_socram_banksize(sysmem, idx, &banksize); 63805491d2cSKalle Valo memsize += banksize; 63905491d2cSKalle Valo } 64005491d2cSKalle Valo 64105491d2cSKalle Valo return memsize; 64205491d2cSKalle Valo } 64305491d2cSKalle Valo 64405491d2cSKalle Valo /** Return the TCM-RAM size of the ARMCR4 core. */ 64505491d2cSKalle Valo static u32 brcmf_chip_tcm_ramsize(struct brcmf_core_priv *cr4) 64605491d2cSKalle Valo { 64705491d2cSKalle Valo u32 corecap; 64805491d2cSKalle Valo u32 memsize = 0; 64905491d2cSKalle Valo u32 nab; 65005491d2cSKalle Valo u32 nbb; 65105491d2cSKalle Valo u32 totb; 65205491d2cSKalle Valo u32 bxinfo; 65305491d2cSKalle Valo u32 idx; 65405491d2cSKalle Valo 65505491d2cSKalle Valo corecap = brcmf_chip_core_read32(cr4, ARMCR4_CAP); 65605491d2cSKalle Valo 65705491d2cSKalle Valo nab = (corecap & ARMCR4_TCBANB_MASK) >> ARMCR4_TCBANB_SHIFT; 65805491d2cSKalle Valo nbb = (corecap & ARMCR4_TCBBNB_MASK) >> ARMCR4_TCBBNB_SHIFT; 65905491d2cSKalle Valo totb = nab + nbb; 66005491d2cSKalle Valo 66105491d2cSKalle Valo for (idx = 0; idx < totb; idx++) { 66205491d2cSKalle Valo brcmf_chip_core_write32(cr4, ARMCR4_BANKIDX, idx); 66305491d2cSKalle Valo bxinfo = brcmf_chip_core_read32(cr4, ARMCR4_BANKINFO); 66405491d2cSKalle Valo memsize += ((bxinfo & ARMCR4_BSZ_MASK) + 1) * ARMCR4_BSZ_MULT; 66505491d2cSKalle Valo } 66605491d2cSKalle Valo 66705491d2cSKalle Valo return memsize; 66805491d2cSKalle Valo } 66905491d2cSKalle Valo 67005491d2cSKalle Valo static u32 brcmf_chip_tcm_rambase(struct brcmf_chip_priv *ci) 67105491d2cSKalle Valo { 67205491d2cSKalle Valo switch (ci->pub.chip) { 67305491d2cSKalle Valo case BRCM_CC_4345_CHIP_ID: 67405491d2cSKalle Valo return 0x198000; 67505491d2cSKalle Valo case BRCM_CC_4335_CHIP_ID: 67605491d2cSKalle Valo case BRCM_CC_4339_CHIP_ID: 67705491d2cSKalle Valo case BRCM_CC_4350_CHIP_ID: 67805491d2cSKalle Valo case BRCM_CC_4354_CHIP_ID: 67905491d2cSKalle Valo case BRCM_CC_4356_CHIP_ID: 68005491d2cSKalle Valo case BRCM_CC_43567_CHIP_ID: 68105491d2cSKalle Valo case BRCM_CC_43569_CHIP_ID: 68205491d2cSKalle Valo case BRCM_CC_43570_CHIP_ID: 68305491d2cSKalle Valo case BRCM_CC_4358_CHIP_ID: 6842aff0303SHante Meuleman case BRCM_CC_4359_CHIP_ID: 68505491d2cSKalle Valo case BRCM_CC_43602_CHIP_ID: 68605491d2cSKalle Valo case BRCM_CC_4371_CHIP_ID: 68705491d2cSKalle Valo return 0x180000; 68843819926SHante Meuleman case BRCM_CC_43465_CHIP_ID: 68943819926SHante Meuleman case BRCM_CC_43525_CHIP_ID: 69005491d2cSKalle Valo case BRCM_CC_4365_CHIP_ID: 69105491d2cSKalle Valo case BRCM_CC_4366_CHIP_ID: 69205491d2cSKalle Valo return 0x200000; 693*0ec9eb90SChi-Hsien Lin case CY_CC_4373_CHIP_ID: 694*0ec9eb90SChi-Hsien Lin return 0x160000; 69505491d2cSKalle Valo default: 69605491d2cSKalle Valo brcmf_err("unknown chip: %s\n", ci->pub.name); 69705491d2cSKalle Valo break; 69805491d2cSKalle Valo } 69905491d2cSKalle Valo return 0; 70005491d2cSKalle Valo } 70105491d2cSKalle Valo 70205491d2cSKalle Valo static int brcmf_chip_get_raminfo(struct brcmf_chip_priv *ci) 70305491d2cSKalle Valo { 70405491d2cSKalle Valo struct brcmf_core_priv *mem_core; 70505491d2cSKalle Valo struct brcmf_core *mem; 70605491d2cSKalle Valo 70705491d2cSKalle Valo mem = brcmf_chip_get_core(&ci->pub, BCMA_CORE_ARM_CR4); 70805491d2cSKalle Valo if (mem) { 70905491d2cSKalle Valo mem_core = container_of(mem, struct brcmf_core_priv, pub); 71005491d2cSKalle Valo ci->pub.ramsize = brcmf_chip_tcm_ramsize(mem_core); 71105491d2cSKalle Valo ci->pub.rambase = brcmf_chip_tcm_rambase(ci); 71205491d2cSKalle Valo if (!ci->pub.rambase) { 71305491d2cSKalle Valo brcmf_err("RAM base not provided with ARM CR4 core\n"); 71405491d2cSKalle Valo return -EINVAL; 71505491d2cSKalle Valo } 71605491d2cSKalle Valo } else { 71705491d2cSKalle Valo mem = brcmf_chip_get_core(&ci->pub, BCMA_CORE_SYS_MEM); 71805491d2cSKalle Valo if (mem) { 71905491d2cSKalle Valo mem_core = container_of(mem, struct brcmf_core_priv, 72005491d2cSKalle Valo pub); 72105491d2cSKalle Valo ci->pub.ramsize = brcmf_chip_sysmem_ramsize(mem_core); 72205491d2cSKalle Valo ci->pub.rambase = brcmf_chip_tcm_rambase(ci); 72305491d2cSKalle Valo if (!ci->pub.rambase) { 72405491d2cSKalle Valo brcmf_err("RAM base not provided with ARM CA7 core\n"); 72505491d2cSKalle Valo return -EINVAL; 72605491d2cSKalle Valo } 72705491d2cSKalle Valo } else { 72805491d2cSKalle Valo mem = brcmf_chip_get_core(&ci->pub, 72905491d2cSKalle Valo BCMA_CORE_INTERNAL_MEM); 73005491d2cSKalle Valo if (!mem) { 73105491d2cSKalle Valo brcmf_err("No memory cores found\n"); 73205491d2cSKalle Valo return -ENOMEM; 73305491d2cSKalle Valo } 73405491d2cSKalle Valo mem_core = container_of(mem, struct brcmf_core_priv, 73505491d2cSKalle Valo pub); 73605491d2cSKalle Valo brcmf_chip_socram_ramsize(mem_core, &ci->pub.ramsize, 73705491d2cSKalle Valo &ci->pub.srsize); 73805491d2cSKalle Valo } 73905491d2cSKalle Valo } 74005491d2cSKalle Valo brcmf_dbg(INFO, "RAM: base=0x%x size=%d (0x%x) sr=%d (0x%x)\n", 74105491d2cSKalle Valo ci->pub.rambase, ci->pub.ramsize, ci->pub.ramsize, 74205491d2cSKalle Valo ci->pub.srsize, ci->pub.srsize); 74305491d2cSKalle Valo 74405491d2cSKalle Valo if (!ci->pub.ramsize) { 74505491d2cSKalle Valo brcmf_err("RAM size is undetermined\n"); 74605491d2cSKalle Valo return -ENOMEM; 74705491d2cSKalle Valo } 74805491d2cSKalle Valo 74905491d2cSKalle Valo if (ci->pub.ramsize > BRCMF_CHIP_MAX_MEMSIZE) { 75005491d2cSKalle Valo brcmf_err("RAM size is incorrect\n"); 75105491d2cSKalle Valo return -ENOMEM; 75205491d2cSKalle Valo } 75305491d2cSKalle Valo 75405491d2cSKalle Valo return 0; 75505491d2cSKalle Valo } 75605491d2cSKalle Valo 75705491d2cSKalle Valo static u32 brcmf_chip_dmp_get_desc(struct brcmf_chip_priv *ci, u32 *eromaddr, 75805491d2cSKalle Valo u8 *type) 75905491d2cSKalle Valo { 76005491d2cSKalle Valo u32 val; 76105491d2cSKalle Valo 76205491d2cSKalle Valo /* read next descriptor */ 76305491d2cSKalle Valo val = ci->ops->read32(ci->ctx, *eromaddr); 76405491d2cSKalle Valo *eromaddr += 4; 76505491d2cSKalle Valo 76605491d2cSKalle Valo if (!type) 76705491d2cSKalle Valo return val; 76805491d2cSKalle Valo 76905491d2cSKalle Valo /* determine descriptor type */ 77005491d2cSKalle Valo *type = (val & DMP_DESC_TYPE_MSK); 77105491d2cSKalle Valo if ((*type & ~DMP_DESC_ADDRSIZE_GT32) == DMP_DESC_ADDRESS) 77205491d2cSKalle Valo *type = DMP_DESC_ADDRESS; 77305491d2cSKalle Valo 77405491d2cSKalle Valo return val; 77505491d2cSKalle Valo } 77605491d2cSKalle Valo 77705491d2cSKalle Valo static int brcmf_chip_dmp_get_regaddr(struct brcmf_chip_priv *ci, u32 *eromaddr, 77805491d2cSKalle Valo u32 *regbase, u32 *wrapbase) 77905491d2cSKalle Valo { 78005491d2cSKalle Valo u8 desc; 78105491d2cSKalle Valo u32 val; 78205491d2cSKalle Valo u8 mpnum = 0; 78305491d2cSKalle Valo u8 stype, sztype, wraptype; 78405491d2cSKalle Valo 78505491d2cSKalle Valo *regbase = 0; 78605491d2cSKalle Valo *wrapbase = 0; 78705491d2cSKalle Valo 78805491d2cSKalle Valo val = brcmf_chip_dmp_get_desc(ci, eromaddr, &desc); 78905491d2cSKalle Valo if (desc == DMP_DESC_MASTER_PORT) { 79005491d2cSKalle Valo mpnum = (val & DMP_MASTER_PORT_NUM) >> DMP_MASTER_PORT_NUM_S; 79105491d2cSKalle Valo wraptype = DMP_SLAVE_TYPE_MWRAP; 79205491d2cSKalle Valo } else if (desc == DMP_DESC_ADDRESS) { 79305491d2cSKalle Valo /* revert erom address */ 79405491d2cSKalle Valo *eromaddr -= 4; 79505491d2cSKalle Valo wraptype = DMP_SLAVE_TYPE_SWRAP; 79605491d2cSKalle Valo } else { 79705491d2cSKalle Valo *eromaddr -= 4; 79805491d2cSKalle Valo return -EILSEQ; 79905491d2cSKalle Valo } 80005491d2cSKalle Valo 80105491d2cSKalle Valo do { 80205491d2cSKalle Valo /* locate address descriptor */ 80305491d2cSKalle Valo do { 80405491d2cSKalle Valo val = brcmf_chip_dmp_get_desc(ci, eromaddr, &desc); 80505491d2cSKalle Valo /* unexpected table end */ 80605491d2cSKalle Valo if (desc == DMP_DESC_EOT) { 80705491d2cSKalle Valo *eromaddr -= 4; 80805491d2cSKalle Valo return -EFAULT; 80905491d2cSKalle Valo } 810a4f4abd0SRafał Miłecki } while (desc != DMP_DESC_ADDRESS && 811a4f4abd0SRafał Miłecki desc != DMP_DESC_COMPONENT); 812a4f4abd0SRafał Miłecki 813a4f4abd0SRafał Miłecki /* stop if we crossed current component border */ 814a4f4abd0SRafał Miłecki if (desc == DMP_DESC_COMPONENT) { 815a4f4abd0SRafał Miłecki *eromaddr -= 4; 816a4f4abd0SRafał Miłecki return 0; 817a4f4abd0SRafał Miłecki } 81805491d2cSKalle Valo 81905491d2cSKalle Valo /* skip upper 32-bit address descriptor */ 82005491d2cSKalle Valo if (val & DMP_DESC_ADDRSIZE_GT32) 82105491d2cSKalle Valo brcmf_chip_dmp_get_desc(ci, eromaddr, NULL); 82205491d2cSKalle Valo 82305491d2cSKalle Valo sztype = (val & DMP_SLAVE_SIZE_TYPE) >> DMP_SLAVE_SIZE_TYPE_S; 82405491d2cSKalle Valo 82505491d2cSKalle Valo /* next size descriptor can be skipped */ 82605491d2cSKalle Valo if (sztype == DMP_SLAVE_SIZE_DESC) { 82705491d2cSKalle Valo val = brcmf_chip_dmp_get_desc(ci, eromaddr, NULL); 82805491d2cSKalle Valo /* skip upper size descriptor if present */ 82905491d2cSKalle Valo if (val & DMP_DESC_ADDRSIZE_GT32) 83005491d2cSKalle Valo brcmf_chip_dmp_get_desc(ci, eromaddr, NULL); 83105491d2cSKalle Valo } 83205491d2cSKalle Valo 83305491d2cSKalle Valo /* only look for 4K register regions */ 83405491d2cSKalle Valo if (sztype != DMP_SLAVE_SIZE_4K) 83505491d2cSKalle Valo continue; 83605491d2cSKalle Valo 83705491d2cSKalle Valo stype = (val & DMP_SLAVE_TYPE) >> DMP_SLAVE_TYPE_S; 83805491d2cSKalle Valo 83905491d2cSKalle Valo /* only regular slave and wrapper */ 84005491d2cSKalle Valo if (*regbase == 0 && stype == DMP_SLAVE_TYPE_SLAVE) 84105491d2cSKalle Valo *regbase = val & DMP_SLAVE_ADDR_BASE; 84205491d2cSKalle Valo if (*wrapbase == 0 && stype == wraptype) 84305491d2cSKalle Valo *wrapbase = val & DMP_SLAVE_ADDR_BASE; 84405491d2cSKalle Valo } while (*regbase == 0 || *wrapbase == 0); 84505491d2cSKalle Valo 84605491d2cSKalle Valo return 0; 84705491d2cSKalle Valo } 84805491d2cSKalle Valo 84905491d2cSKalle Valo static 85005491d2cSKalle Valo int brcmf_chip_dmp_erom_scan(struct brcmf_chip_priv *ci) 85105491d2cSKalle Valo { 85205491d2cSKalle Valo struct brcmf_core *core; 85305491d2cSKalle Valo u32 eromaddr; 85405491d2cSKalle Valo u8 desc_type = 0; 85505491d2cSKalle Valo u32 val; 85605491d2cSKalle Valo u16 id; 85705491d2cSKalle Valo u8 nmp, nsp, nmw, nsw, rev; 85805491d2cSKalle Valo u32 base, wrap; 85905491d2cSKalle Valo int err; 86005491d2cSKalle Valo 86105491d2cSKalle Valo eromaddr = ci->ops->read32(ci->ctx, CORE_CC_REG(SI_ENUM_BASE, eromptr)); 86205491d2cSKalle Valo 86305491d2cSKalle Valo while (desc_type != DMP_DESC_EOT) { 86405491d2cSKalle Valo val = brcmf_chip_dmp_get_desc(ci, &eromaddr, &desc_type); 86505491d2cSKalle Valo if (!(val & DMP_DESC_VALID)) 86605491d2cSKalle Valo continue; 86705491d2cSKalle Valo 86805491d2cSKalle Valo if (desc_type == DMP_DESC_EMPTY) 86905491d2cSKalle Valo continue; 87005491d2cSKalle Valo 87105491d2cSKalle Valo /* need a component descriptor */ 87205491d2cSKalle Valo if (desc_type != DMP_DESC_COMPONENT) 87305491d2cSKalle Valo continue; 87405491d2cSKalle Valo 87505491d2cSKalle Valo id = (val & DMP_COMP_PARTNUM) >> DMP_COMP_PARTNUM_S; 87605491d2cSKalle Valo 87705491d2cSKalle Valo /* next descriptor must be component as well */ 87805491d2cSKalle Valo val = brcmf_chip_dmp_get_desc(ci, &eromaddr, &desc_type); 87905491d2cSKalle Valo if (WARN_ON((val & DMP_DESC_TYPE_MSK) != DMP_DESC_COMPONENT)) 88005491d2cSKalle Valo return -EFAULT; 88105491d2cSKalle Valo 88205491d2cSKalle Valo /* only look at cores with master port(s) */ 88305491d2cSKalle Valo nmp = (val & DMP_COMP_NUM_MPORT) >> DMP_COMP_NUM_MPORT_S; 88405491d2cSKalle Valo nsp = (val & DMP_COMP_NUM_SPORT) >> DMP_COMP_NUM_SPORT_S; 88505491d2cSKalle Valo nmw = (val & DMP_COMP_NUM_MWRAP) >> DMP_COMP_NUM_MWRAP_S; 88605491d2cSKalle Valo nsw = (val & DMP_COMP_NUM_SWRAP) >> DMP_COMP_NUM_SWRAP_S; 88705491d2cSKalle Valo rev = (val & DMP_COMP_REVISION) >> DMP_COMP_REVISION_S; 88805491d2cSKalle Valo 88905491d2cSKalle Valo /* need core with ports */ 89044977b81SRafał Miłecki if (nmw + nsw == 0 && 89144977b81SRafał Miłecki id != BCMA_CORE_PMU) 89205491d2cSKalle Valo continue; 89305491d2cSKalle Valo 89405491d2cSKalle Valo /* try to obtain register address info */ 89505491d2cSKalle Valo err = brcmf_chip_dmp_get_regaddr(ci, &eromaddr, &base, &wrap); 89605491d2cSKalle Valo if (err) 89705491d2cSKalle Valo continue; 89805491d2cSKalle Valo 89905491d2cSKalle Valo /* finally a core to be added */ 90005491d2cSKalle Valo core = brcmf_chip_add_core(ci, id, base, wrap); 90105491d2cSKalle Valo if (IS_ERR(core)) 90205491d2cSKalle Valo return PTR_ERR(core); 90305491d2cSKalle Valo 90405491d2cSKalle Valo core->rev = rev; 90505491d2cSKalle Valo } 90605491d2cSKalle Valo 90705491d2cSKalle Valo return 0; 90805491d2cSKalle Valo } 90905491d2cSKalle Valo 91005491d2cSKalle Valo static int brcmf_chip_recognition(struct brcmf_chip_priv *ci) 91105491d2cSKalle Valo { 91205491d2cSKalle Valo struct brcmf_core *core; 91305491d2cSKalle Valo u32 regdata; 91405491d2cSKalle Valo u32 socitype; 91505491d2cSKalle Valo int ret; 91605491d2cSKalle Valo 91705491d2cSKalle Valo /* Get CC core rev 91805491d2cSKalle Valo * Chipid is assume to be at offset 0 from SI_ENUM_BASE 91905491d2cSKalle Valo * For different chiptypes or old sdio hosts w/o chipcommon, 92005491d2cSKalle Valo * other ways of recognition should be added here. 92105491d2cSKalle Valo */ 92205491d2cSKalle Valo regdata = ci->ops->read32(ci->ctx, CORE_CC_REG(SI_ENUM_BASE, chipid)); 92305491d2cSKalle Valo ci->pub.chip = regdata & CID_ID_MASK; 92405491d2cSKalle Valo ci->pub.chiprev = (regdata & CID_REV_MASK) >> CID_REV_SHIFT; 92505491d2cSKalle Valo socitype = (regdata & CID_TYPE_MASK) >> CID_TYPE_SHIFT; 92605491d2cSKalle Valo 92705491d2cSKalle Valo brcmf_chip_name(ci->pub.chip, ci->pub.name, sizeof(ci->pub.name)); 92805491d2cSKalle Valo brcmf_dbg(INFO, "found %s chip: BCM%s, rev=%d\n", 92905491d2cSKalle Valo socitype == SOCI_SB ? "SB" : "AXI", ci->pub.name, 93005491d2cSKalle Valo ci->pub.chiprev); 93105491d2cSKalle Valo 93205491d2cSKalle Valo if (socitype == SOCI_SB) { 93305491d2cSKalle Valo if (ci->pub.chip != BRCM_CC_4329_CHIP_ID) { 93405491d2cSKalle Valo brcmf_err("SB chip is not supported\n"); 93505491d2cSKalle Valo return -ENODEV; 93605491d2cSKalle Valo } 93705491d2cSKalle Valo ci->iscoreup = brcmf_chip_sb_iscoreup; 93805491d2cSKalle Valo ci->coredisable = brcmf_chip_sb_coredisable; 93905491d2cSKalle Valo ci->resetcore = brcmf_chip_sb_resetcore; 94005491d2cSKalle Valo 94105491d2cSKalle Valo core = brcmf_chip_add_core(ci, BCMA_CORE_CHIPCOMMON, 94205491d2cSKalle Valo SI_ENUM_BASE, 0); 94305491d2cSKalle Valo brcmf_chip_sb_corerev(ci, core); 94405491d2cSKalle Valo core = brcmf_chip_add_core(ci, BCMA_CORE_SDIO_DEV, 94505491d2cSKalle Valo BCM4329_CORE_BUS_BASE, 0); 94605491d2cSKalle Valo brcmf_chip_sb_corerev(ci, core); 94705491d2cSKalle Valo core = brcmf_chip_add_core(ci, BCMA_CORE_INTERNAL_MEM, 94805491d2cSKalle Valo BCM4329_CORE_SOCRAM_BASE, 0); 94905491d2cSKalle Valo brcmf_chip_sb_corerev(ci, core); 95005491d2cSKalle Valo core = brcmf_chip_add_core(ci, BCMA_CORE_ARM_CM3, 95105491d2cSKalle Valo BCM4329_CORE_ARM_BASE, 0); 95205491d2cSKalle Valo brcmf_chip_sb_corerev(ci, core); 95305491d2cSKalle Valo 95405491d2cSKalle Valo core = brcmf_chip_add_core(ci, BCMA_CORE_80211, 0x18001000, 0); 95505491d2cSKalle Valo brcmf_chip_sb_corerev(ci, core); 95605491d2cSKalle Valo } else if (socitype == SOCI_AI) { 95705491d2cSKalle Valo ci->iscoreup = brcmf_chip_ai_iscoreup; 95805491d2cSKalle Valo ci->coredisable = brcmf_chip_ai_coredisable; 95905491d2cSKalle Valo ci->resetcore = brcmf_chip_ai_resetcore; 96005491d2cSKalle Valo 96105491d2cSKalle Valo brcmf_chip_dmp_erom_scan(ci); 96205491d2cSKalle Valo } else { 96305491d2cSKalle Valo brcmf_err("chip backplane type %u is not supported\n", 96405491d2cSKalle Valo socitype); 96505491d2cSKalle Valo return -ENODEV; 96605491d2cSKalle Valo } 96705491d2cSKalle Valo 96805491d2cSKalle Valo ret = brcmf_chip_cores_check(ci); 96905491d2cSKalle Valo if (ret) 97005491d2cSKalle Valo return ret; 97105491d2cSKalle Valo 97205491d2cSKalle Valo /* assure chip is passive for core access */ 97305491d2cSKalle Valo brcmf_chip_set_passive(&ci->pub); 97405491d2cSKalle Valo 97505491d2cSKalle Valo /* Call bus specific reset function now. Cores have been determined 97605491d2cSKalle Valo * but further access may require a chip specific reset at this point. 97705491d2cSKalle Valo */ 97805491d2cSKalle Valo if (ci->ops->reset) { 97905491d2cSKalle Valo ci->ops->reset(ci->ctx, &ci->pub); 98005491d2cSKalle Valo brcmf_chip_set_passive(&ci->pub); 98105491d2cSKalle Valo } 98205491d2cSKalle Valo 98305491d2cSKalle Valo return brcmf_chip_get_raminfo(ci); 98405491d2cSKalle Valo } 98505491d2cSKalle Valo 98605491d2cSKalle Valo static void brcmf_chip_disable_arm(struct brcmf_chip_priv *chip, u16 id) 98705491d2cSKalle Valo { 98805491d2cSKalle Valo struct brcmf_core *core; 98905491d2cSKalle Valo struct brcmf_core_priv *cpu; 99005491d2cSKalle Valo u32 val; 99105491d2cSKalle Valo 99205491d2cSKalle Valo 99305491d2cSKalle Valo core = brcmf_chip_get_core(&chip->pub, id); 99405491d2cSKalle Valo if (!core) 99505491d2cSKalle Valo return; 99605491d2cSKalle Valo 99705491d2cSKalle Valo switch (id) { 99805491d2cSKalle Valo case BCMA_CORE_ARM_CM3: 99905491d2cSKalle Valo brcmf_chip_coredisable(core, 0, 0); 100005491d2cSKalle Valo break; 100105491d2cSKalle Valo case BCMA_CORE_ARM_CR4: 100205491d2cSKalle Valo case BCMA_CORE_ARM_CA7: 100305491d2cSKalle Valo cpu = container_of(core, struct brcmf_core_priv, pub); 100405491d2cSKalle Valo 100505491d2cSKalle Valo /* clear all IOCTL bits except HALT bit */ 100605491d2cSKalle Valo val = chip->ops->read32(chip->ctx, cpu->wrapbase + BCMA_IOCTL); 100705491d2cSKalle Valo val &= ARMCR4_BCMA_IOCTL_CPUHALT; 100805491d2cSKalle Valo brcmf_chip_resetcore(core, val, ARMCR4_BCMA_IOCTL_CPUHALT, 100905491d2cSKalle Valo ARMCR4_BCMA_IOCTL_CPUHALT); 101005491d2cSKalle Valo break; 101105491d2cSKalle Valo default: 101205491d2cSKalle Valo brcmf_err("unknown id: %u\n", id); 101305491d2cSKalle Valo break; 101405491d2cSKalle Valo } 101505491d2cSKalle Valo } 101605491d2cSKalle Valo 101705491d2cSKalle Valo static int brcmf_chip_setup(struct brcmf_chip_priv *chip) 101805491d2cSKalle Valo { 101905491d2cSKalle Valo struct brcmf_chip *pub; 102005491d2cSKalle Valo struct brcmf_core_priv *cc; 1021e2b397f1SRafał Miłecki struct brcmf_core *pmu; 102205491d2cSKalle Valo u32 base; 102305491d2cSKalle Valo u32 val; 102405491d2cSKalle Valo int ret = 0; 102505491d2cSKalle Valo 102605491d2cSKalle Valo pub = &chip->pub; 102705491d2cSKalle Valo cc = list_first_entry(&chip->cores, struct brcmf_core_priv, list); 102805491d2cSKalle Valo base = cc->pub.base; 102905491d2cSKalle Valo 103005491d2cSKalle Valo /* get chipcommon capabilites */ 103105491d2cSKalle Valo pub->cc_caps = chip->ops->read32(chip->ctx, 103205491d2cSKalle Valo CORE_CC_REG(base, capabilities)); 10339befe919SRafał Miłecki pub->cc_caps_ext = chip->ops->read32(chip->ctx, 10349befe919SRafał Miłecki CORE_CC_REG(base, 10359befe919SRafał Miłecki capabilities_ext)); 103605491d2cSKalle Valo 103705491d2cSKalle Valo /* get pmu caps & rev */ 1038e2b397f1SRafał Miłecki pmu = brcmf_chip_get_pmu(pub); /* after reading cc_caps_ext */ 103905491d2cSKalle Valo if (pub->cc_caps & CC_CAP_PMU) { 104005491d2cSKalle Valo val = chip->ops->read32(chip->ctx, 1041e2b397f1SRafał Miłecki CORE_CC_REG(pmu->base, pmucapabilities)); 104205491d2cSKalle Valo pub->pmurev = val & PCAP_REV_MASK; 104305491d2cSKalle Valo pub->pmucaps = val; 104405491d2cSKalle Valo } 104505491d2cSKalle Valo 104605491d2cSKalle Valo brcmf_dbg(INFO, "ccrev=%d, pmurev=%d, pmucaps=0x%x\n", 104705491d2cSKalle Valo cc->pub.rev, pub->pmurev, pub->pmucaps); 104805491d2cSKalle Valo 104905491d2cSKalle Valo /* execute bus core specific setup */ 105005491d2cSKalle Valo if (chip->ops->setup) 105105491d2cSKalle Valo ret = chip->ops->setup(chip->ctx, pub); 105205491d2cSKalle Valo 105305491d2cSKalle Valo return ret; 105405491d2cSKalle Valo } 105505491d2cSKalle Valo 105605491d2cSKalle Valo struct brcmf_chip *brcmf_chip_attach(void *ctx, 105705491d2cSKalle Valo const struct brcmf_buscore_ops *ops) 105805491d2cSKalle Valo { 105905491d2cSKalle Valo struct brcmf_chip_priv *chip; 106005491d2cSKalle Valo int err = 0; 106105491d2cSKalle Valo 106205491d2cSKalle Valo if (WARN_ON(!ops->read32)) 106305491d2cSKalle Valo err = -EINVAL; 106405491d2cSKalle Valo if (WARN_ON(!ops->write32)) 106505491d2cSKalle Valo err = -EINVAL; 106605491d2cSKalle Valo if (WARN_ON(!ops->prepare)) 106705491d2cSKalle Valo err = -EINVAL; 106805491d2cSKalle Valo if (WARN_ON(!ops->activate)) 106905491d2cSKalle Valo err = -EINVAL; 107005491d2cSKalle Valo if (err < 0) 107105491d2cSKalle Valo return ERR_PTR(-EINVAL); 107205491d2cSKalle Valo 107305491d2cSKalle Valo chip = kzalloc(sizeof(*chip), GFP_KERNEL); 107405491d2cSKalle Valo if (!chip) 107505491d2cSKalle Valo return ERR_PTR(-ENOMEM); 107605491d2cSKalle Valo 107705491d2cSKalle Valo INIT_LIST_HEAD(&chip->cores); 107805491d2cSKalle Valo chip->num_cores = 0; 107905491d2cSKalle Valo chip->ops = ops; 108005491d2cSKalle Valo chip->ctx = ctx; 108105491d2cSKalle Valo 108205491d2cSKalle Valo err = ops->prepare(ctx); 108305491d2cSKalle Valo if (err < 0) 108405491d2cSKalle Valo goto fail; 108505491d2cSKalle Valo 108605491d2cSKalle Valo err = brcmf_chip_recognition(chip); 108705491d2cSKalle Valo if (err < 0) 108805491d2cSKalle Valo goto fail; 108905491d2cSKalle Valo 109005491d2cSKalle Valo err = brcmf_chip_setup(chip); 109105491d2cSKalle Valo if (err < 0) 109205491d2cSKalle Valo goto fail; 109305491d2cSKalle Valo 109405491d2cSKalle Valo return &chip->pub; 109505491d2cSKalle Valo 109605491d2cSKalle Valo fail: 109705491d2cSKalle Valo brcmf_chip_detach(&chip->pub); 109805491d2cSKalle Valo return ERR_PTR(err); 109905491d2cSKalle Valo } 110005491d2cSKalle Valo 110105491d2cSKalle Valo void brcmf_chip_detach(struct brcmf_chip *pub) 110205491d2cSKalle Valo { 110305491d2cSKalle Valo struct brcmf_chip_priv *chip; 110405491d2cSKalle Valo struct brcmf_core_priv *core; 110505491d2cSKalle Valo struct brcmf_core_priv *tmp; 110605491d2cSKalle Valo 110705491d2cSKalle Valo chip = container_of(pub, struct brcmf_chip_priv, pub); 110805491d2cSKalle Valo list_for_each_entry_safe(core, tmp, &chip->cores, list) { 110905491d2cSKalle Valo list_del(&core->list); 111005491d2cSKalle Valo kfree(core); 111105491d2cSKalle Valo } 111205491d2cSKalle Valo kfree(chip); 111305491d2cSKalle Valo } 111405491d2cSKalle Valo 111505491d2cSKalle Valo struct brcmf_core *brcmf_chip_get_core(struct brcmf_chip *pub, u16 coreid) 111605491d2cSKalle Valo { 111705491d2cSKalle Valo struct brcmf_chip_priv *chip; 111805491d2cSKalle Valo struct brcmf_core_priv *core; 111905491d2cSKalle Valo 112005491d2cSKalle Valo chip = container_of(pub, struct brcmf_chip_priv, pub); 112105491d2cSKalle Valo list_for_each_entry(core, &chip->cores, list) 112205491d2cSKalle Valo if (core->pub.id == coreid) 112305491d2cSKalle Valo return &core->pub; 112405491d2cSKalle Valo 112505491d2cSKalle Valo return NULL; 112605491d2cSKalle Valo } 112705491d2cSKalle Valo 112805491d2cSKalle Valo struct brcmf_core *brcmf_chip_get_chipcommon(struct brcmf_chip *pub) 112905491d2cSKalle Valo { 113005491d2cSKalle Valo struct brcmf_chip_priv *chip; 113105491d2cSKalle Valo struct brcmf_core_priv *cc; 113205491d2cSKalle Valo 113305491d2cSKalle Valo chip = container_of(pub, struct brcmf_chip_priv, pub); 113405491d2cSKalle Valo cc = list_first_entry(&chip->cores, struct brcmf_core_priv, list); 113505491d2cSKalle Valo if (WARN_ON(!cc || cc->pub.id != BCMA_CORE_CHIPCOMMON)) 113605491d2cSKalle Valo return brcmf_chip_get_core(pub, BCMA_CORE_CHIPCOMMON); 113705491d2cSKalle Valo return &cc->pub; 113805491d2cSKalle Valo } 113905491d2cSKalle Valo 1140e2b397f1SRafał Miłecki struct brcmf_core *brcmf_chip_get_pmu(struct brcmf_chip *pub) 1141e2b397f1SRafał Miłecki { 1142e2b397f1SRafał Miłecki struct brcmf_core *cc = brcmf_chip_get_chipcommon(pub); 1143e2b397f1SRafał Miłecki struct brcmf_core *pmu; 1144e2b397f1SRafał Miłecki 1145e2b397f1SRafał Miłecki /* See if there is separated PMU core available */ 1146e2b397f1SRafał Miłecki if (cc->rev >= 35 && 1147e2b397f1SRafał Miłecki pub->cc_caps_ext & BCMA_CC_CAP_EXT_AOB_PRESENT) { 1148e2b397f1SRafał Miłecki pmu = brcmf_chip_get_core(pub, BCMA_CORE_PMU); 1149e2b397f1SRafał Miłecki if (pmu) 1150e2b397f1SRafał Miłecki return pmu; 1151e2b397f1SRafał Miłecki } 1152e2b397f1SRafał Miłecki 1153e2b397f1SRafał Miłecki /* Fallback to ChipCommon core for older hardware */ 1154e2b397f1SRafał Miłecki return cc; 1155e2b397f1SRafał Miłecki } 1156e2b397f1SRafał Miłecki 115705491d2cSKalle Valo bool brcmf_chip_iscoreup(struct brcmf_core *pub) 115805491d2cSKalle Valo { 115905491d2cSKalle Valo struct brcmf_core_priv *core; 116005491d2cSKalle Valo 116105491d2cSKalle Valo core = container_of(pub, struct brcmf_core_priv, pub); 116205491d2cSKalle Valo return core->chip->iscoreup(core); 116305491d2cSKalle Valo } 116405491d2cSKalle Valo 116505491d2cSKalle Valo void brcmf_chip_coredisable(struct brcmf_core *pub, u32 prereset, u32 reset) 116605491d2cSKalle Valo { 116705491d2cSKalle Valo struct brcmf_core_priv *core; 116805491d2cSKalle Valo 116905491d2cSKalle Valo core = container_of(pub, struct brcmf_core_priv, pub); 117005491d2cSKalle Valo core->chip->coredisable(core, prereset, reset); 117105491d2cSKalle Valo } 117205491d2cSKalle Valo 117305491d2cSKalle Valo void brcmf_chip_resetcore(struct brcmf_core *pub, u32 prereset, u32 reset, 117405491d2cSKalle Valo u32 postreset) 117505491d2cSKalle Valo { 117605491d2cSKalle Valo struct brcmf_core_priv *core; 117705491d2cSKalle Valo 117805491d2cSKalle Valo core = container_of(pub, struct brcmf_core_priv, pub); 117905491d2cSKalle Valo core->chip->resetcore(core, prereset, reset, postreset); 118005491d2cSKalle Valo } 118105491d2cSKalle Valo 118205491d2cSKalle Valo static void 118305491d2cSKalle Valo brcmf_chip_cm3_set_passive(struct brcmf_chip_priv *chip) 118405491d2cSKalle Valo { 118505491d2cSKalle Valo struct brcmf_core *core; 118605491d2cSKalle Valo struct brcmf_core_priv *sr; 118705491d2cSKalle Valo 118805491d2cSKalle Valo brcmf_chip_disable_arm(chip, BCMA_CORE_ARM_CM3); 118905491d2cSKalle Valo core = brcmf_chip_get_core(&chip->pub, BCMA_CORE_80211); 119005491d2cSKalle Valo brcmf_chip_resetcore(core, D11_BCMA_IOCTL_PHYRESET | 119105491d2cSKalle Valo D11_BCMA_IOCTL_PHYCLOCKEN, 119205491d2cSKalle Valo D11_BCMA_IOCTL_PHYCLOCKEN, 119305491d2cSKalle Valo D11_BCMA_IOCTL_PHYCLOCKEN); 119405491d2cSKalle Valo core = brcmf_chip_get_core(&chip->pub, BCMA_CORE_INTERNAL_MEM); 119505491d2cSKalle Valo brcmf_chip_resetcore(core, 0, 0, 0); 119605491d2cSKalle Valo 119705491d2cSKalle Valo /* disable bank #3 remap for this device */ 119805491d2cSKalle Valo if (chip->pub.chip == BRCM_CC_43430_CHIP_ID) { 119905491d2cSKalle Valo sr = container_of(core, struct brcmf_core_priv, pub); 120005491d2cSKalle Valo brcmf_chip_core_write32(sr, SOCRAMREGOFFS(bankidx), 3); 120105491d2cSKalle Valo brcmf_chip_core_write32(sr, SOCRAMREGOFFS(bankpda), 0); 120205491d2cSKalle Valo } 120305491d2cSKalle Valo } 120405491d2cSKalle Valo 120505491d2cSKalle Valo static bool brcmf_chip_cm3_set_active(struct brcmf_chip_priv *chip) 120605491d2cSKalle Valo { 120705491d2cSKalle Valo struct brcmf_core *core; 120805491d2cSKalle Valo 120905491d2cSKalle Valo core = brcmf_chip_get_core(&chip->pub, BCMA_CORE_INTERNAL_MEM); 121005491d2cSKalle Valo if (!brcmf_chip_iscoreup(core)) { 121105491d2cSKalle Valo brcmf_err("SOCRAM core is down after reset?\n"); 121205491d2cSKalle Valo return false; 121305491d2cSKalle Valo } 121405491d2cSKalle Valo 121505491d2cSKalle Valo chip->ops->activate(chip->ctx, &chip->pub, 0); 121605491d2cSKalle Valo 121705491d2cSKalle Valo core = brcmf_chip_get_core(&chip->pub, BCMA_CORE_ARM_CM3); 121805491d2cSKalle Valo brcmf_chip_resetcore(core, 0, 0, 0); 121905491d2cSKalle Valo 122005491d2cSKalle Valo return true; 122105491d2cSKalle Valo } 122205491d2cSKalle Valo 122305491d2cSKalle Valo static inline void 122405491d2cSKalle Valo brcmf_chip_cr4_set_passive(struct brcmf_chip_priv *chip) 122505491d2cSKalle Valo { 122605491d2cSKalle Valo struct brcmf_core *core; 122705491d2cSKalle Valo 122805491d2cSKalle Valo brcmf_chip_disable_arm(chip, BCMA_CORE_ARM_CR4); 122905491d2cSKalle Valo 123005491d2cSKalle Valo core = brcmf_chip_get_core(&chip->pub, BCMA_CORE_80211); 123105491d2cSKalle Valo brcmf_chip_resetcore(core, D11_BCMA_IOCTL_PHYRESET | 123205491d2cSKalle Valo D11_BCMA_IOCTL_PHYCLOCKEN, 123305491d2cSKalle Valo D11_BCMA_IOCTL_PHYCLOCKEN, 123405491d2cSKalle Valo D11_BCMA_IOCTL_PHYCLOCKEN); 123505491d2cSKalle Valo } 123605491d2cSKalle Valo 123705491d2cSKalle Valo static bool brcmf_chip_cr4_set_active(struct brcmf_chip_priv *chip, u32 rstvec) 123805491d2cSKalle Valo { 123905491d2cSKalle Valo struct brcmf_core *core; 124005491d2cSKalle Valo 124105491d2cSKalle Valo chip->ops->activate(chip->ctx, &chip->pub, rstvec); 124205491d2cSKalle Valo 124305491d2cSKalle Valo /* restore ARM */ 124405491d2cSKalle Valo core = brcmf_chip_get_core(&chip->pub, BCMA_CORE_ARM_CR4); 124505491d2cSKalle Valo brcmf_chip_resetcore(core, ARMCR4_BCMA_IOCTL_CPUHALT, 0, 0); 124605491d2cSKalle Valo 124705491d2cSKalle Valo return true; 124805491d2cSKalle Valo } 124905491d2cSKalle Valo 125005491d2cSKalle Valo static inline void 125105491d2cSKalle Valo brcmf_chip_ca7_set_passive(struct brcmf_chip_priv *chip) 125205491d2cSKalle Valo { 125305491d2cSKalle Valo struct brcmf_core *core; 125405491d2cSKalle Valo 125505491d2cSKalle Valo brcmf_chip_disable_arm(chip, BCMA_CORE_ARM_CA7); 125605491d2cSKalle Valo 125705491d2cSKalle Valo core = brcmf_chip_get_core(&chip->pub, BCMA_CORE_80211); 125805491d2cSKalle Valo brcmf_chip_resetcore(core, D11_BCMA_IOCTL_PHYRESET | 125905491d2cSKalle Valo D11_BCMA_IOCTL_PHYCLOCKEN, 126005491d2cSKalle Valo D11_BCMA_IOCTL_PHYCLOCKEN, 126105491d2cSKalle Valo D11_BCMA_IOCTL_PHYCLOCKEN); 126205491d2cSKalle Valo } 126305491d2cSKalle Valo 126405491d2cSKalle Valo static bool brcmf_chip_ca7_set_active(struct brcmf_chip_priv *chip, u32 rstvec) 126505491d2cSKalle Valo { 126605491d2cSKalle Valo struct brcmf_core *core; 126705491d2cSKalle Valo 126805491d2cSKalle Valo chip->ops->activate(chip->ctx, &chip->pub, rstvec); 126905491d2cSKalle Valo 127005491d2cSKalle Valo /* restore ARM */ 127105491d2cSKalle Valo core = brcmf_chip_get_core(&chip->pub, BCMA_CORE_ARM_CA7); 127205491d2cSKalle Valo brcmf_chip_resetcore(core, ARMCR4_BCMA_IOCTL_CPUHALT, 0, 0); 127305491d2cSKalle Valo 127405491d2cSKalle Valo return true; 127505491d2cSKalle Valo } 127605491d2cSKalle Valo 127705491d2cSKalle Valo void brcmf_chip_set_passive(struct brcmf_chip *pub) 127805491d2cSKalle Valo { 127905491d2cSKalle Valo struct brcmf_chip_priv *chip; 128005491d2cSKalle Valo struct brcmf_core *arm; 128105491d2cSKalle Valo 128205491d2cSKalle Valo brcmf_dbg(TRACE, "Enter\n"); 128305491d2cSKalle Valo 128405491d2cSKalle Valo chip = container_of(pub, struct brcmf_chip_priv, pub); 128505491d2cSKalle Valo arm = brcmf_chip_get_core(pub, BCMA_CORE_ARM_CR4); 128605491d2cSKalle Valo if (arm) { 128705491d2cSKalle Valo brcmf_chip_cr4_set_passive(chip); 128805491d2cSKalle Valo return; 128905491d2cSKalle Valo } 129005491d2cSKalle Valo arm = brcmf_chip_get_core(pub, BCMA_CORE_ARM_CA7); 129105491d2cSKalle Valo if (arm) { 129205491d2cSKalle Valo brcmf_chip_ca7_set_passive(chip); 129305491d2cSKalle Valo return; 129405491d2cSKalle Valo } 129505491d2cSKalle Valo arm = brcmf_chip_get_core(pub, BCMA_CORE_ARM_CM3); 129605491d2cSKalle Valo if (arm) { 129705491d2cSKalle Valo brcmf_chip_cm3_set_passive(chip); 129805491d2cSKalle Valo return; 129905491d2cSKalle Valo } 130005491d2cSKalle Valo } 130105491d2cSKalle Valo 130205491d2cSKalle Valo bool brcmf_chip_set_active(struct brcmf_chip *pub, u32 rstvec) 130305491d2cSKalle Valo { 130405491d2cSKalle Valo struct brcmf_chip_priv *chip; 130505491d2cSKalle Valo struct brcmf_core *arm; 130605491d2cSKalle Valo 130705491d2cSKalle Valo brcmf_dbg(TRACE, "Enter\n"); 130805491d2cSKalle Valo 130905491d2cSKalle Valo chip = container_of(pub, struct brcmf_chip_priv, pub); 131005491d2cSKalle Valo arm = brcmf_chip_get_core(pub, BCMA_CORE_ARM_CR4); 131105491d2cSKalle Valo if (arm) 131205491d2cSKalle Valo return brcmf_chip_cr4_set_active(chip, rstvec); 131305491d2cSKalle Valo arm = brcmf_chip_get_core(pub, BCMA_CORE_ARM_CA7); 131405491d2cSKalle Valo if (arm) 131505491d2cSKalle Valo return brcmf_chip_ca7_set_active(chip, rstvec); 131605491d2cSKalle Valo arm = brcmf_chip_get_core(pub, BCMA_CORE_ARM_CM3); 131705491d2cSKalle Valo if (arm) 131805491d2cSKalle Valo return brcmf_chip_cm3_set_active(chip); 131905491d2cSKalle Valo 132005491d2cSKalle Valo return false; 132105491d2cSKalle Valo } 132205491d2cSKalle Valo 132305491d2cSKalle Valo bool brcmf_chip_sr_capable(struct brcmf_chip *pub) 132405491d2cSKalle Valo { 132505491d2cSKalle Valo u32 base, addr, reg, pmu_cc3_mask = ~0; 132605491d2cSKalle Valo struct brcmf_chip_priv *chip; 1327e2b397f1SRafał Miłecki struct brcmf_core *pmu = brcmf_chip_get_pmu(pub); 132805491d2cSKalle Valo 132905491d2cSKalle Valo brcmf_dbg(TRACE, "Enter\n"); 133005491d2cSKalle Valo 133105491d2cSKalle Valo /* old chips with PMU version less than 17 don't support save restore */ 133205491d2cSKalle Valo if (pub->pmurev < 17) 133305491d2cSKalle Valo return false; 133405491d2cSKalle Valo 133505491d2cSKalle Valo base = brcmf_chip_get_chipcommon(pub)->base; 133605491d2cSKalle Valo chip = container_of(pub, struct brcmf_chip_priv, pub); 133705491d2cSKalle Valo 133805491d2cSKalle Valo switch (pub->chip) { 133905491d2cSKalle Valo case BRCM_CC_4354_CHIP_ID: 1340496aec57SChristian Daudt case BRCM_CC_4356_CHIP_ID: 134105491d2cSKalle Valo /* explicitly check SR engine enable bit */ 134205491d2cSKalle Valo pmu_cc3_mask = BIT(2); 134305491d2cSKalle Valo /* fall-through */ 134405491d2cSKalle Valo case BRCM_CC_43241_CHIP_ID: 134505491d2cSKalle Valo case BRCM_CC_4335_CHIP_ID: 134605491d2cSKalle Valo case BRCM_CC_4339_CHIP_ID: 134705491d2cSKalle Valo /* read PMU chipcontrol register 3 */ 1348e2b397f1SRafał Miłecki addr = CORE_CC_REG(pmu->base, chipcontrol_addr); 134905491d2cSKalle Valo chip->ops->write32(chip->ctx, addr, 3); 1350e2b397f1SRafał Miłecki addr = CORE_CC_REG(pmu->base, chipcontrol_data); 135105491d2cSKalle Valo reg = chip->ops->read32(chip->ctx, addr); 135205491d2cSKalle Valo return (reg & pmu_cc3_mask) != 0; 135305491d2cSKalle Valo case BRCM_CC_43430_CHIP_ID: 135405491d2cSKalle Valo addr = CORE_CC_REG(base, sr_control1); 135505491d2cSKalle Valo reg = chip->ops->read32(chip->ctx, addr); 135605491d2cSKalle Valo return reg != 0; 135705491d2cSKalle Valo default: 1358e2b397f1SRafał Miłecki addr = CORE_CC_REG(pmu->base, pmucapabilities_ext); 135905491d2cSKalle Valo reg = chip->ops->read32(chip->ctx, addr); 136005491d2cSKalle Valo if ((reg & PCAPEXT_SR_SUPPORTED_MASK) == 0) 136105491d2cSKalle Valo return false; 136205491d2cSKalle Valo 1363e2b397f1SRafał Miłecki addr = CORE_CC_REG(pmu->base, retention_ctl); 136405491d2cSKalle Valo reg = chip->ops->read32(chip->ctx, addr); 136505491d2cSKalle Valo return (reg & (PMU_RCTL_MACPHY_DISABLE_MASK | 136605491d2cSKalle Valo PMU_RCTL_LOGIC_DISABLE_MASK)) == 0; 136705491d2cSKalle Valo } 136805491d2cSKalle Valo } 1369