162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Broadcom specific AMBA 362306a36Sopenharmony_ci * Core ops 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Licensed under the GNU/GPL. See COPYING for details. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include "bcma_private.h" 962306a36Sopenharmony_ci#include <linux/export.h> 1062306a36Sopenharmony_ci#include <linux/bcma/bcma.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_cistatic bool bcma_core_wait_value(struct bcma_device *core, u16 reg, u32 mask, 1362306a36Sopenharmony_ci u32 value, int timeout) 1462306a36Sopenharmony_ci{ 1562306a36Sopenharmony_ci unsigned long deadline = jiffies + timeout; 1662306a36Sopenharmony_ci u32 val; 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci do { 1962306a36Sopenharmony_ci val = bcma_aread32(core, reg); 2062306a36Sopenharmony_ci if ((val & mask) == value) 2162306a36Sopenharmony_ci return true; 2262306a36Sopenharmony_ci cpu_relax(); 2362306a36Sopenharmony_ci udelay(10); 2462306a36Sopenharmony_ci } while (!time_after_eq(jiffies, deadline)); 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci bcma_warn(core->bus, "Timeout waiting for register 0x%04X!\n", reg); 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci return false; 2962306a36Sopenharmony_ci} 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cibool bcma_core_is_enabled(struct bcma_device *core) 3262306a36Sopenharmony_ci{ 3362306a36Sopenharmony_ci if ((bcma_aread32(core, BCMA_IOCTL) & (BCMA_IOCTL_CLK | BCMA_IOCTL_FGC)) 3462306a36Sopenharmony_ci != BCMA_IOCTL_CLK) 3562306a36Sopenharmony_ci return false; 3662306a36Sopenharmony_ci if (bcma_aread32(core, BCMA_RESET_CTL) & BCMA_RESET_CTL_RESET) 3762306a36Sopenharmony_ci return false; 3862306a36Sopenharmony_ci return true; 3962306a36Sopenharmony_ci} 4062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(bcma_core_is_enabled); 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_civoid bcma_core_disable(struct bcma_device *core, u32 flags) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci if (bcma_aread32(core, BCMA_RESET_CTL) & BCMA_RESET_CTL_RESET) 4562306a36Sopenharmony_ci return; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci bcma_core_wait_value(core, BCMA_RESET_ST, ~0, 0, 300); 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci bcma_awrite32(core, BCMA_RESET_CTL, BCMA_RESET_CTL_RESET); 5062306a36Sopenharmony_ci bcma_aread32(core, BCMA_RESET_CTL); 5162306a36Sopenharmony_ci udelay(1); 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci bcma_awrite32(core, BCMA_IOCTL, flags); 5462306a36Sopenharmony_ci bcma_aread32(core, BCMA_IOCTL); 5562306a36Sopenharmony_ci udelay(10); 5662306a36Sopenharmony_ci} 5762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(bcma_core_disable); 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ciint bcma_core_enable(struct bcma_device *core, u32 flags) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci bcma_core_disable(core, flags); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci bcma_awrite32(core, BCMA_IOCTL, (BCMA_IOCTL_CLK | BCMA_IOCTL_FGC | flags)); 6462306a36Sopenharmony_ci bcma_aread32(core, BCMA_IOCTL); 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci bcma_awrite32(core, BCMA_RESET_CTL, 0); 6762306a36Sopenharmony_ci bcma_aread32(core, BCMA_RESET_CTL); 6862306a36Sopenharmony_ci udelay(1); 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci bcma_awrite32(core, BCMA_IOCTL, (BCMA_IOCTL_CLK | flags)); 7162306a36Sopenharmony_ci bcma_aread32(core, BCMA_IOCTL); 7262306a36Sopenharmony_ci udelay(1); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci return 0; 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(bcma_core_enable); 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_civoid bcma_core_set_clockmode(struct bcma_device *core, 7962306a36Sopenharmony_ci enum bcma_clkmode clkmode) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci u16 i; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci WARN_ON(core->id.id != BCMA_CORE_CHIPCOMMON && 8462306a36Sopenharmony_ci core->id.id != BCMA_CORE_PCIE && 8562306a36Sopenharmony_ci core->id.id != BCMA_CORE_80211); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci switch (clkmode) { 8862306a36Sopenharmony_ci case BCMA_CLKMODE_FAST: 8962306a36Sopenharmony_ci bcma_set32(core, BCMA_CLKCTLST, BCMA_CLKCTLST_FORCEHT); 9062306a36Sopenharmony_ci usleep_range(64, 300); 9162306a36Sopenharmony_ci for (i = 0; i < 1500; i++) { 9262306a36Sopenharmony_ci if (bcma_read32(core, BCMA_CLKCTLST) & 9362306a36Sopenharmony_ci BCMA_CLKCTLST_HAVEHT) { 9462306a36Sopenharmony_ci i = 0; 9562306a36Sopenharmony_ci break; 9662306a36Sopenharmony_ci } 9762306a36Sopenharmony_ci udelay(10); 9862306a36Sopenharmony_ci } 9962306a36Sopenharmony_ci if (i) 10062306a36Sopenharmony_ci bcma_err(core->bus, "HT force timeout\n"); 10162306a36Sopenharmony_ci break; 10262306a36Sopenharmony_ci case BCMA_CLKMODE_DYNAMIC: 10362306a36Sopenharmony_ci bcma_set32(core, BCMA_CLKCTLST, ~BCMA_CLKCTLST_FORCEHT); 10462306a36Sopenharmony_ci break; 10562306a36Sopenharmony_ci } 10662306a36Sopenharmony_ci} 10762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(bcma_core_set_clockmode); 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_civoid bcma_core_pll_ctl(struct bcma_device *core, u32 req, u32 status, bool on) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci u16 i; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci WARN_ON(req & ~BCMA_CLKCTLST_EXTRESREQ); 11462306a36Sopenharmony_ci WARN_ON(status & ~BCMA_CLKCTLST_EXTRESST); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci if (on) { 11762306a36Sopenharmony_ci bcma_set32(core, BCMA_CLKCTLST, req); 11862306a36Sopenharmony_ci for (i = 0; i < 10000; i++) { 11962306a36Sopenharmony_ci if ((bcma_read32(core, BCMA_CLKCTLST) & status) == 12062306a36Sopenharmony_ci status) { 12162306a36Sopenharmony_ci i = 0; 12262306a36Sopenharmony_ci break; 12362306a36Sopenharmony_ci } 12462306a36Sopenharmony_ci udelay(10); 12562306a36Sopenharmony_ci } 12662306a36Sopenharmony_ci if (i) 12762306a36Sopenharmony_ci bcma_err(core->bus, "PLL enable timeout\n"); 12862306a36Sopenharmony_ci } else { 12962306a36Sopenharmony_ci /* 13062306a36Sopenharmony_ci * Mask the PLL but don't wait for it to be disabled. PLL may be 13162306a36Sopenharmony_ci * shared between cores and will be still up if there is another 13262306a36Sopenharmony_ci * core using it. 13362306a36Sopenharmony_ci */ 13462306a36Sopenharmony_ci bcma_mask32(core, BCMA_CLKCTLST, ~req); 13562306a36Sopenharmony_ci bcma_read32(core, BCMA_CLKCTLST); 13662306a36Sopenharmony_ci } 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(bcma_core_pll_ctl); 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ciu32 bcma_core_dma_translation(struct bcma_device *core) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci switch (core->bus->hosttype) { 14362306a36Sopenharmony_ci case BCMA_HOSTTYPE_SOC: 14462306a36Sopenharmony_ci return 0; 14562306a36Sopenharmony_ci case BCMA_HOSTTYPE_PCI: 14662306a36Sopenharmony_ci if (bcma_aread32(core, BCMA_IOST) & BCMA_IOST_DMA64) 14762306a36Sopenharmony_ci return BCMA_DMA_TRANSLATION_DMA64_CMT; 14862306a36Sopenharmony_ci else 14962306a36Sopenharmony_ci return BCMA_DMA_TRANSLATION_DMA32_CMT; 15062306a36Sopenharmony_ci default: 15162306a36Sopenharmony_ci bcma_err(core->bus, "DMA translation unknown for host %d\n", 15262306a36Sopenharmony_ci core->bus->hosttype); 15362306a36Sopenharmony_ci } 15462306a36Sopenharmony_ci return BCMA_DMA_TRANSLATION_NONE; 15562306a36Sopenharmony_ci} 15662306a36Sopenharmony_ciEXPORT_SYMBOL(bcma_core_dma_translation); 157