Blame view
arch/x86/lib/pmu.c
2.06 KB
d41ce506b Initial Release, ... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
/* * Copyright (c) 2017 Intel Corporation * * SPDX-License-Identifier: GPL-2.0+ */ #include <common.h> #include <dm.h> #include <regmap.h> #include <syscon.h> #include <asm/cpu.h> #include <asm/pmu.h> #include <linux/errno.h> #include <linux/io.h> /* Registers */ struct pmu_regs { u32 sts; u32 cmd; u32 ics; u32 reserved; u32 wkc[4]; u32 wks[4]; u32 ssc[4]; u32 sss[4]; }; /* Bits in PMU_REGS_STS */ #define PMU_REGS_STS_BUSY (1 << 8) struct pmu_mid { struct pmu_regs *regs; }; static int pmu_read_status(struct pmu_regs *regs) { int retry = 500000; u32 val; do { val = readl(®s->sts); if (!(val & PMU_REGS_STS_BUSY)) return 0; udelay(1); } while (--retry); printf("WARNING: PMU still busy "); return -EBUSY; } static int pmu_power_lss(struct pmu_regs *regs, unsigned int lss, bool on) { unsigned int offset = (lss * 2) / 32; unsigned int shift = (lss * 2) % 32; u32 ssc; int ret; /* Check PMU status */ ret = pmu_read_status(regs); if (ret) return ret; /* Read PMU values */ ssc = readl(®s->sss[offset]); /* Modify PMU values */ if (on) ssc &= ~(0x3 << shift); /* D0 */ else ssc |= 0x3 << shift; /* D3hot */ /* Write modified PMU values */ writel(ssc, ®s->ssc[offset]); /* Update modified PMU values */ writel(0x00002201, ®s->cmd); /* Check PMU status */ return pmu_read_status(regs); } int pmu_turn_power(unsigned int lss, bool on) { struct pmu_mid *pmu; struct udevice *dev; int ret; ret = syscon_get_by_driver_data(X86_SYSCON_PMU, &dev); if (ret) return ret; pmu = dev_get_priv(dev); return pmu_power_lss(pmu->regs, lss, on); } static int pmu_mid_probe(struct udevice *dev) { struct pmu_mid *pmu = dev_get_priv(dev); pmu->regs = syscon_get_first_range(X86_SYSCON_PMU); return 0; } static const struct udevice_id pmu_mid_match[] = { { .compatible = "intel,pmu-mid", .data = X86_SYSCON_PMU }, { /* sentinel */ } }; U_BOOT_DRIVER(intel_mid_pmu) = { .name = "pmu_mid", .id = UCLASS_SYSCON, .of_match = pmu_mid_match, .probe = pmu_mid_probe, .priv_auto_alloc_size = sizeof(struct pmu_mid), }; |