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