#include <linux/pci.h>
#include <linux/io-64-nonatomic-lo-hi.h>
#include "core.h"
#define SSRAM_HDR_SIZE 0x100
#define SSRAM_PWRM_OFFSET 0x14
#define SSRAM_DVSEC_OFFSET 0x1C
#define SSRAM_DVSEC_SIZE 0x10
#define SSRAM_PCH_OFFSET 0x60
#define SSRAM_IOE_OFFSET 0x68
#define SSRAM_DEVID_OFFSET 0x70
static const struct pmc_reg_map *pmc_core_find_regmap(struct pmc_info *list, u16 devid)
{
for (; list->map; ++list)
if (devid == list->devid)
return list->map;
return NULL;
}
static inline u64 get_base(void __iomem *addr, u32 offset)
{
return lo_hi_readq(addr + offset) & GENMASK_ULL(63, 3);
}
static void
pmc_core_pmc_add(struct pmc_dev *pmcdev, u64 pwrm_base,
const struct pmc_reg_map *reg_map, int pmc_index)
{
struct pmc *pmc = pmcdev->pmcs[pmc_index];
if (!pwrm_base)
return;
if (!pmc) {
pmc = devm_kzalloc(&pmcdev->pdev->dev, sizeof(*pmc), GFP_KERNEL);
if (!pmc)
return;
}
pmc->map = reg_map;
pmc->base_addr = pwrm_base;
pmc->regbase = ioremap(pmc->base_addr, pmc->map->regmap_length);
if (!pmc->regbase) {
devm_kfree(&pmcdev->pdev->dev, pmc);
return;
}
pmcdev->pmcs[pmc_index] = pmc;
}
static void
pmc_core_ssram_get_pmc(struct pmc_dev *pmcdev, void __iomem *ssram, u32 offset,
int pmc_idx)
{
u64 pwrm_base;
u16 devid;
if (pmc_idx != PMC_IDX_SOC) {
u64 ssram_base = get_base(ssram, offset);
if (!ssram_base)
return;
ssram = ioremap(ssram_base, SSRAM_HDR_SIZE);
if (!ssram)
return;
}
pwrm_base = get_base(ssram, SSRAM_PWRM_OFFSET);
devid = readw(ssram + SSRAM_DEVID_OFFSET);
if (pmcdev->regmap_list) {
const struct pmc_reg_map *map;
map = pmc_core_find_regmap(pmcdev->regmap_list, devid);
if (map)
pmc_core_pmc_add(pmcdev, pwrm_base, map, pmc_idx);
}
if (pmc_idx != PMC_IDX_SOC)
iounmap(ssram);
}
void pmc_core_ssram_init(struct pmc_dev *pmcdev)
{
void __iomem *ssram;
struct pci_dev *pcidev;
u64 ssram_base;
int ret;
pcidev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(20, 2));
if (!pcidev)
goto out;
ret = pcim_enable_device(pcidev);
if (ret)
goto release_dev;
ssram_base = pcidev->resource[0].start;
ssram = ioremap(ssram_base, SSRAM_HDR_SIZE);
if (!ssram)
goto disable_dev;
pmcdev->ssram_pcidev = pcidev;
pmc_core_ssram_get_pmc(pmcdev, ssram, 0, PMC_IDX_SOC);
pmc_core_ssram_get_pmc(pmcdev, ssram, SSRAM_IOE_OFFSET, PMC_IDX_IOE);
pmc_core_ssram_get_pmc(pmcdev, ssram, SSRAM_PCH_OFFSET, PMC_IDX_PCH);
iounmap(ssram);
out:
return;
disable_dev:
pci_disable_device(pcidev);
release_dev:
pci_dev_put(pcidev);
}