18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Broadcom specific AMBA 38c2ecf20Sopenharmony_ci * Core ops 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Licensed under the GNU/GPL. See COPYING for details. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include "bcma_private.h" 98c2ecf20Sopenharmony_ci#include <linux/export.h> 108c2ecf20Sopenharmony_ci#include <linux/bcma/bcma.h> 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_cistatic bool bcma_core_wait_value(struct bcma_device *core, u16 reg, u32 mask, 138c2ecf20Sopenharmony_ci u32 value, int timeout) 148c2ecf20Sopenharmony_ci{ 158c2ecf20Sopenharmony_ci unsigned long deadline = jiffies + timeout; 168c2ecf20Sopenharmony_ci u32 val; 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci do { 198c2ecf20Sopenharmony_ci val = bcma_aread32(core, reg); 208c2ecf20Sopenharmony_ci if ((val & mask) == value) 218c2ecf20Sopenharmony_ci return true; 228c2ecf20Sopenharmony_ci cpu_relax(); 238c2ecf20Sopenharmony_ci udelay(10); 248c2ecf20Sopenharmony_ci } while (!time_after_eq(jiffies, deadline)); 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci bcma_warn(core->bus, "Timeout waiting for register 0x%04X!\n", reg); 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci return false; 298c2ecf20Sopenharmony_ci} 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cibool bcma_core_is_enabled(struct bcma_device *core) 328c2ecf20Sopenharmony_ci{ 338c2ecf20Sopenharmony_ci if ((bcma_aread32(core, BCMA_IOCTL) & (BCMA_IOCTL_CLK | BCMA_IOCTL_FGC)) 348c2ecf20Sopenharmony_ci != BCMA_IOCTL_CLK) 358c2ecf20Sopenharmony_ci return false; 368c2ecf20Sopenharmony_ci if (bcma_aread32(core, BCMA_RESET_CTL) & BCMA_RESET_CTL_RESET) 378c2ecf20Sopenharmony_ci return false; 388c2ecf20Sopenharmony_ci return true; 398c2ecf20Sopenharmony_ci} 408c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(bcma_core_is_enabled); 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_civoid bcma_core_disable(struct bcma_device *core, u32 flags) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci if (bcma_aread32(core, BCMA_RESET_CTL) & BCMA_RESET_CTL_RESET) 458c2ecf20Sopenharmony_ci return; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci bcma_core_wait_value(core, BCMA_RESET_ST, ~0, 0, 300); 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci bcma_awrite32(core, BCMA_RESET_CTL, BCMA_RESET_CTL_RESET); 508c2ecf20Sopenharmony_ci bcma_aread32(core, BCMA_RESET_CTL); 518c2ecf20Sopenharmony_ci udelay(1); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci bcma_awrite32(core, BCMA_IOCTL, flags); 548c2ecf20Sopenharmony_ci bcma_aread32(core, BCMA_IOCTL); 558c2ecf20Sopenharmony_ci udelay(10); 568c2ecf20Sopenharmony_ci} 578c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(bcma_core_disable); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ciint bcma_core_enable(struct bcma_device *core, u32 flags) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci bcma_core_disable(core, flags); 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci bcma_awrite32(core, BCMA_IOCTL, (BCMA_IOCTL_CLK | BCMA_IOCTL_FGC | flags)); 648c2ecf20Sopenharmony_ci bcma_aread32(core, BCMA_IOCTL); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci bcma_awrite32(core, BCMA_RESET_CTL, 0); 678c2ecf20Sopenharmony_ci bcma_aread32(core, BCMA_RESET_CTL); 688c2ecf20Sopenharmony_ci udelay(1); 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci bcma_awrite32(core, BCMA_IOCTL, (BCMA_IOCTL_CLK | flags)); 718c2ecf20Sopenharmony_ci bcma_aread32(core, BCMA_IOCTL); 728c2ecf20Sopenharmony_ci udelay(1); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci return 0; 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(bcma_core_enable); 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_civoid bcma_core_set_clockmode(struct bcma_device *core, 798c2ecf20Sopenharmony_ci enum bcma_clkmode clkmode) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci u16 i; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci WARN_ON(core->id.id != BCMA_CORE_CHIPCOMMON && 848c2ecf20Sopenharmony_ci core->id.id != BCMA_CORE_PCIE && 858c2ecf20Sopenharmony_ci core->id.id != BCMA_CORE_80211); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci switch (clkmode) { 888c2ecf20Sopenharmony_ci case BCMA_CLKMODE_FAST: 898c2ecf20Sopenharmony_ci bcma_set32(core, BCMA_CLKCTLST, BCMA_CLKCTLST_FORCEHT); 908c2ecf20Sopenharmony_ci usleep_range(64, 300); 918c2ecf20Sopenharmony_ci for (i = 0; i < 1500; i++) { 928c2ecf20Sopenharmony_ci if (bcma_read32(core, BCMA_CLKCTLST) & 938c2ecf20Sopenharmony_ci BCMA_CLKCTLST_HAVEHT) { 948c2ecf20Sopenharmony_ci i = 0; 958c2ecf20Sopenharmony_ci break; 968c2ecf20Sopenharmony_ci } 978c2ecf20Sopenharmony_ci udelay(10); 988c2ecf20Sopenharmony_ci } 998c2ecf20Sopenharmony_ci if (i) 1008c2ecf20Sopenharmony_ci bcma_err(core->bus, "HT force timeout\n"); 1018c2ecf20Sopenharmony_ci break; 1028c2ecf20Sopenharmony_ci case BCMA_CLKMODE_DYNAMIC: 1038c2ecf20Sopenharmony_ci bcma_set32(core, BCMA_CLKCTLST, ~BCMA_CLKCTLST_FORCEHT); 1048c2ecf20Sopenharmony_ci break; 1058c2ecf20Sopenharmony_ci } 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(bcma_core_set_clockmode); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_civoid bcma_core_pll_ctl(struct bcma_device *core, u32 req, u32 status, bool on) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci u16 i; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci WARN_ON(req & ~BCMA_CLKCTLST_EXTRESREQ); 1148c2ecf20Sopenharmony_ci WARN_ON(status & ~BCMA_CLKCTLST_EXTRESST); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci if (on) { 1178c2ecf20Sopenharmony_ci bcma_set32(core, BCMA_CLKCTLST, req); 1188c2ecf20Sopenharmony_ci for (i = 0; i < 10000; i++) { 1198c2ecf20Sopenharmony_ci if ((bcma_read32(core, BCMA_CLKCTLST) & status) == 1208c2ecf20Sopenharmony_ci status) { 1218c2ecf20Sopenharmony_ci i = 0; 1228c2ecf20Sopenharmony_ci break; 1238c2ecf20Sopenharmony_ci } 1248c2ecf20Sopenharmony_ci udelay(10); 1258c2ecf20Sopenharmony_ci } 1268c2ecf20Sopenharmony_ci if (i) 1278c2ecf20Sopenharmony_ci bcma_err(core->bus, "PLL enable timeout\n"); 1288c2ecf20Sopenharmony_ci } else { 1298c2ecf20Sopenharmony_ci /* 1308c2ecf20Sopenharmony_ci * Mask the PLL but don't wait for it to be disabled. PLL may be 1318c2ecf20Sopenharmony_ci * shared between cores and will be still up if there is another 1328c2ecf20Sopenharmony_ci * core using it. 1338c2ecf20Sopenharmony_ci */ 1348c2ecf20Sopenharmony_ci bcma_mask32(core, BCMA_CLKCTLST, ~req); 1358c2ecf20Sopenharmony_ci bcma_read32(core, BCMA_CLKCTLST); 1368c2ecf20Sopenharmony_ci } 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(bcma_core_pll_ctl); 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ciu32 bcma_core_dma_translation(struct bcma_device *core) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci switch (core->bus->hosttype) { 1438c2ecf20Sopenharmony_ci case BCMA_HOSTTYPE_SOC: 1448c2ecf20Sopenharmony_ci return 0; 1458c2ecf20Sopenharmony_ci case BCMA_HOSTTYPE_PCI: 1468c2ecf20Sopenharmony_ci if (bcma_aread32(core, BCMA_IOST) & BCMA_IOST_DMA64) 1478c2ecf20Sopenharmony_ci return BCMA_DMA_TRANSLATION_DMA64_CMT; 1488c2ecf20Sopenharmony_ci else 1498c2ecf20Sopenharmony_ci return BCMA_DMA_TRANSLATION_DMA32_CMT; 1508c2ecf20Sopenharmony_ci default: 1518c2ecf20Sopenharmony_ci bcma_err(core->bus, "DMA translation unknown for host %d\n", 1528c2ecf20Sopenharmony_ci core->bus->hosttype); 1538c2ecf20Sopenharmony_ci } 1548c2ecf20Sopenharmony_ci return BCMA_DMA_TRANSLATION_NONE; 1558c2ecf20Sopenharmony_ci} 1568c2ecf20Sopenharmony_ciEXPORT_SYMBOL(bcma_core_dma_translation); 157