18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Broadcom specific AMBA
38c2ecf20Sopenharmony_ci * PCIe Gen 2 Core
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright 2014, Broadcom Corporation
68c2ecf20Sopenharmony_ci * Copyright 2014, Rafał Miłecki <zajec5@gmail.com>
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Licensed under the GNU/GPL. See COPYING for details.
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include "bcma_private.h"
128c2ecf20Sopenharmony_ci#include <linux/bcma/bcma.h>
138c2ecf20Sopenharmony_ci#include <linux/pci.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci/**************************************************
168c2ecf20Sopenharmony_ci * R/W ops.
178c2ecf20Sopenharmony_ci **************************************************/
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#if 0
208c2ecf20Sopenharmony_cistatic u32 bcma_core_pcie2_cfg_read(struct bcma_drv_pcie2 *pcie2, u32 addr)
218c2ecf20Sopenharmony_ci{
228c2ecf20Sopenharmony_ci	pcie2_write32(pcie2, BCMA_CORE_PCIE2_CONFIGINDADDR, addr);
238c2ecf20Sopenharmony_ci	pcie2_read32(pcie2, BCMA_CORE_PCIE2_CONFIGINDADDR);
248c2ecf20Sopenharmony_ci	return pcie2_read32(pcie2, BCMA_CORE_PCIE2_CONFIGINDDATA);
258c2ecf20Sopenharmony_ci}
268c2ecf20Sopenharmony_ci#endif
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_cistatic void bcma_core_pcie2_cfg_write(struct bcma_drv_pcie2 *pcie2, u32 addr,
298c2ecf20Sopenharmony_ci				      u32 val)
308c2ecf20Sopenharmony_ci{
318c2ecf20Sopenharmony_ci	pcie2_write32(pcie2, BCMA_CORE_PCIE2_CONFIGINDADDR, addr);
328c2ecf20Sopenharmony_ci	pcie2_write32(pcie2, BCMA_CORE_PCIE2_CONFIGINDDATA, val);
338c2ecf20Sopenharmony_ci}
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci/**************************************************
368c2ecf20Sopenharmony_ci * Init.
378c2ecf20Sopenharmony_ci **************************************************/
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cistatic u32 bcma_core_pcie2_war_delay_perst_enab(struct bcma_drv_pcie2 *pcie2,
408c2ecf20Sopenharmony_ci						bool enable)
418c2ecf20Sopenharmony_ci{
428c2ecf20Sopenharmony_ci	u32 val;
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	/* restore back to default */
458c2ecf20Sopenharmony_ci	val = pcie2_read32(pcie2, BCMA_CORE_PCIE2_CLK_CONTROL);
468c2ecf20Sopenharmony_ci	val |= PCIE2_CLKC_DLYPERST;
478c2ecf20Sopenharmony_ci	val &= ~PCIE2_CLKC_DISSPROMLD;
488c2ecf20Sopenharmony_ci	if (enable) {
498c2ecf20Sopenharmony_ci		val &= ~PCIE2_CLKC_DLYPERST;
508c2ecf20Sopenharmony_ci		val |= PCIE2_CLKC_DISSPROMLD;
518c2ecf20Sopenharmony_ci	}
528c2ecf20Sopenharmony_ci	pcie2_write32(pcie2, (BCMA_CORE_PCIE2_CLK_CONTROL), val);
538c2ecf20Sopenharmony_ci	/* flush */
548c2ecf20Sopenharmony_ci	return pcie2_read32(pcie2, BCMA_CORE_PCIE2_CLK_CONTROL);
558c2ecf20Sopenharmony_ci}
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_cistatic void bcma_core_pcie2_set_ltr_vals(struct bcma_drv_pcie2 *pcie2)
588c2ecf20Sopenharmony_ci{
598c2ecf20Sopenharmony_ci	/* LTR0 */
608c2ecf20Sopenharmony_ci	pcie2_write32(pcie2, BCMA_CORE_PCIE2_CONFIGINDADDR, 0x844);
618c2ecf20Sopenharmony_ci	pcie2_write32(pcie2, BCMA_CORE_PCIE2_CONFIGINDDATA, 0x883c883c);
628c2ecf20Sopenharmony_ci	/* LTR1 */
638c2ecf20Sopenharmony_ci	pcie2_write32(pcie2, BCMA_CORE_PCIE2_CONFIGINDADDR, 0x848);
648c2ecf20Sopenharmony_ci	pcie2_write32(pcie2, BCMA_CORE_PCIE2_CONFIGINDDATA, 0x88648864);
658c2ecf20Sopenharmony_ci	/* LTR2 */
668c2ecf20Sopenharmony_ci	pcie2_write32(pcie2, BCMA_CORE_PCIE2_CONFIGINDADDR, 0x84C);
678c2ecf20Sopenharmony_ci	pcie2_write32(pcie2, BCMA_CORE_PCIE2_CONFIGINDDATA, 0x90039003);
688c2ecf20Sopenharmony_ci}
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_cistatic void bcma_core_pcie2_hw_ltr_war(struct bcma_drv_pcie2 *pcie2)
718c2ecf20Sopenharmony_ci{
728c2ecf20Sopenharmony_ci	u8 core_rev = pcie2->core->id.rev;
738c2ecf20Sopenharmony_ci	u32 devstsctr2;
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	if (core_rev < 2 || core_rev == 10 || core_rev > 13)
768c2ecf20Sopenharmony_ci		return;
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	pcie2_write32(pcie2, BCMA_CORE_PCIE2_CONFIGINDADDR,
798c2ecf20Sopenharmony_ci		      PCIE2_CAP_DEVSTSCTRL2_OFFSET);
808c2ecf20Sopenharmony_ci	devstsctr2 = pcie2_read32(pcie2, BCMA_CORE_PCIE2_CONFIGINDDATA);
818c2ecf20Sopenharmony_ci	if (devstsctr2 & PCIE2_CAP_DEVSTSCTRL2_LTRENAB) {
828c2ecf20Sopenharmony_ci		/* force the right LTR values */
838c2ecf20Sopenharmony_ci		bcma_core_pcie2_set_ltr_vals(pcie2);
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci		/* TODO:
868c2ecf20Sopenharmony_ci		 *si_core_wrapperreg(pcie2, 3, 0x60, 0x8080, 0);
878c2ecf20Sopenharmony_ci		 */
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci		/* enable the LTR */
908c2ecf20Sopenharmony_ci		devstsctr2 |= PCIE2_CAP_DEVSTSCTRL2_LTRENAB;
918c2ecf20Sopenharmony_ci		pcie2_write32(pcie2, BCMA_CORE_PCIE2_CONFIGINDADDR,
928c2ecf20Sopenharmony_ci			      PCIE2_CAP_DEVSTSCTRL2_OFFSET);
938c2ecf20Sopenharmony_ci		pcie2_write32(pcie2, BCMA_CORE_PCIE2_CONFIGINDDATA, devstsctr2);
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci		/* set the LTR state to be active */
968c2ecf20Sopenharmony_ci		pcie2_write32(pcie2, BCMA_CORE_PCIE2_LTR_STATE,
978c2ecf20Sopenharmony_ci			      PCIE2_LTR_ACTIVE);
988c2ecf20Sopenharmony_ci		usleep_range(1000, 2000);
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci		/* set the LTR state to be sleep */
1018c2ecf20Sopenharmony_ci		pcie2_write32(pcie2, BCMA_CORE_PCIE2_LTR_STATE,
1028c2ecf20Sopenharmony_ci			      PCIE2_LTR_SLEEP);
1038c2ecf20Sopenharmony_ci		usleep_range(1000, 2000);
1048c2ecf20Sopenharmony_ci	}
1058c2ecf20Sopenharmony_ci}
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_cistatic void pciedev_crwlpciegen2(struct bcma_drv_pcie2 *pcie2)
1088c2ecf20Sopenharmony_ci{
1098c2ecf20Sopenharmony_ci	u8 core_rev = pcie2->core->id.rev;
1108c2ecf20Sopenharmony_ci	bool pciewar160, pciewar162;
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	pciewar160 = core_rev == 7 || core_rev == 9 || core_rev == 11;
1138c2ecf20Sopenharmony_ci	pciewar162 = core_rev == 5 || core_rev == 7 || core_rev == 8 ||
1148c2ecf20Sopenharmony_ci		     core_rev == 9 || core_rev == 11;
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	if (!pciewar160 && !pciewar162)
1178c2ecf20Sopenharmony_ci		return;
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci/* TODO */
1208c2ecf20Sopenharmony_ci#if 0
1218c2ecf20Sopenharmony_ci	pcie2_set32(pcie2, BCMA_CORE_PCIE2_CLK_CONTROL,
1228c2ecf20Sopenharmony_ci		    PCIE_DISABLE_L1CLK_GATING);
1238c2ecf20Sopenharmony_ci#if 0
1248c2ecf20Sopenharmony_ci	pcie2_write32(pcie2, BCMA_CORE_PCIE2_CONFIGINDADDR,
1258c2ecf20Sopenharmony_ci		      PCIEGEN2_COE_PVT_TL_CTRL_0);
1268c2ecf20Sopenharmony_ci	pcie2_mask32(pcie2, BCMA_CORE_PCIE2_CONFIGINDDATA,
1278c2ecf20Sopenharmony_ci		     ~(1 << COE_PVT_TL_CTRL_0_PM_DIS_L1_REENTRY_BIT));
1288c2ecf20Sopenharmony_ci#endif
1298c2ecf20Sopenharmony_ci#endif
1308c2ecf20Sopenharmony_ci}
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_cistatic void pciedev_crwlpciegen2_180(struct bcma_drv_pcie2 *pcie2)
1338c2ecf20Sopenharmony_ci{
1348c2ecf20Sopenharmony_ci	pcie2_write32(pcie2, BCMA_CORE_PCIE2_CONFIGINDADDR, PCIE2_PMCR_REFUP);
1358c2ecf20Sopenharmony_ci	pcie2_set32(pcie2, BCMA_CORE_PCIE2_CONFIGINDDATA, 0x1f);
1368c2ecf20Sopenharmony_ci}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_cistatic void pciedev_crwlpciegen2_182(struct bcma_drv_pcie2 *pcie2)
1398c2ecf20Sopenharmony_ci{
1408c2ecf20Sopenharmony_ci	pcie2_write32(pcie2, BCMA_CORE_PCIE2_CONFIGINDADDR, PCIE2_SBMBX);
1418c2ecf20Sopenharmony_ci	pcie2_write32(pcie2, BCMA_CORE_PCIE2_CONFIGINDDATA, 1 << 0);
1428c2ecf20Sopenharmony_ci}
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_cistatic void pciedev_reg_pm_clk_period(struct bcma_drv_pcie2 *pcie2)
1458c2ecf20Sopenharmony_ci{
1468c2ecf20Sopenharmony_ci	struct bcma_drv_cc *drv_cc = &pcie2->core->bus->drv_cc;
1478c2ecf20Sopenharmony_ci	u8 core_rev = pcie2->core->id.rev;
1488c2ecf20Sopenharmony_ci	u32 alp_khz, pm_value;
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	if (core_rev <= 13) {
1518c2ecf20Sopenharmony_ci		alp_khz = bcma_pmu_get_alp_clock(drv_cc) / 1000;
1528c2ecf20Sopenharmony_ci		pm_value = (1000000 * 2) / alp_khz;
1538c2ecf20Sopenharmony_ci		pcie2_write32(pcie2, BCMA_CORE_PCIE2_CONFIGINDADDR,
1548c2ecf20Sopenharmony_ci			      PCIE2_PVT_REG_PM_CLK_PERIOD);
1558c2ecf20Sopenharmony_ci		pcie2_write32(pcie2, BCMA_CORE_PCIE2_CONFIGINDDATA, pm_value);
1568c2ecf20Sopenharmony_ci	}
1578c2ecf20Sopenharmony_ci}
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_civoid bcma_core_pcie2_init(struct bcma_drv_pcie2 *pcie2)
1608c2ecf20Sopenharmony_ci{
1618c2ecf20Sopenharmony_ci	struct bcma_bus *bus = pcie2->core->bus;
1628c2ecf20Sopenharmony_ci	struct bcma_chipinfo *ci = &bus->chipinfo;
1638c2ecf20Sopenharmony_ci	u32 tmp;
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	tmp = pcie2_read32(pcie2, BCMA_CORE_PCIE2_SPROM(54));
1668c2ecf20Sopenharmony_ci	if ((tmp & 0xe) >> 1 == 2)
1678c2ecf20Sopenharmony_ci		bcma_core_pcie2_cfg_write(pcie2, 0x4e0, 0x17);
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	switch (bus->chipinfo.id) {
1708c2ecf20Sopenharmony_ci	case BCMA_CHIP_ID_BCM4360:
1718c2ecf20Sopenharmony_ci	case BCMA_CHIP_ID_BCM4352:
1728c2ecf20Sopenharmony_ci		pcie2->reqsize = 1024;
1738c2ecf20Sopenharmony_ci		break;
1748c2ecf20Sopenharmony_ci	default:
1758c2ecf20Sopenharmony_ci		pcie2->reqsize = 128;
1768c2ecf20Sopenharmony_ci		break;
1778c2ecf20Sopenharmony_ci	}
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	if (ci->id == BCMA_CHIP_ID_BCM4360 && ci->rev > 3)
1808c2ecf20Sopenharmony_ci		bcma_core_pcie2_war_delay_perst_enab(pcie2, true);
1818c2ecf20Sopenharmony_ci	bcma_core_pcie2_hw_ltr_war(pcie2);
1828c2ecf20Sopenharmony_ci	pciedev_crwlpciegen2(pcie2);
1838c2ecf20Sopenharmony_ci	pciedev_reg_pm_clk_period(pcie2);
1848c2ecf20Sopenharmony_ci	pciedev_crwlpciegen2_180(pcie2);
1858c2ecf20Sopenharmony_ci	pciedev_crwlpciegen2_182(pcie2);
1868c2ecf20Sopenharmony_ci}
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci/**************************************************
1898c2ecf20Sopenharmony_ci * Runtime ops.
1908c2ecf20Sopenharmony_ci **************************************************/
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_civoid bcma_core_pcie2_up(struct bcma_drv_pcie2 *pcie2)
1938c2ecf20Sopenharmony_ci{
1948c2ecf20Sopenharmony_ci	struct bcma_bus *bus = pcie2->core->bus;
1958c2ecf20Sopenharmony_ci	struct pci_dev *dev = bus->host_pci;
1968c2ecf20Sopenharmony_ci	int err;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	err = pcie_set_readrq(dev, pcie2->reqsize);
1998c2ecf20Sopenharmony_ci	if (err)
2008c2ecf20Sopenharmony_ci		bcma_err(bus, "Error setting PCI_EXP_DEVCTL_READRQ: %d\n", err);
2018c2ecf20Sopenharmony_ci}
202