1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * JH7110 Power Domain Controller Driver
5 * Copyright (C) 2022 StarFive Technology Co., Ltd.
8 #include <dt-bindings/power/jh7110-power.h>
10 #include <linux/iopoll.h>
11 #include <linux/module.h>
12 #include <linux/platform_device.h>
13 #include <linux/interrupt.h>
14 #include <linux/pm_domain.h>
16 #include <linux/of_device.h>
19 #define HW_EVENT_TURN_ON_MASK 0x04
20 #define HW_EVENT_TURN_OFF_MASK 0x08
21 #define SW_TURN_ON_POWER_MODE 0x0C
22 #define SW_TURN_OFF_POWER_MODE 0x10
23 #define SW_ENCOURAGE 0x44
24 #define PMU_INT_MASK 0x48
25 #define PCH_BYPASS 0x4C
26 #define PCH_PSTATE 0x50
27 #define PCH_TIMEOUT 0x54
28 #define LP_TIMEOUT 0x58
29 #define HW_TURN_ON_MODE 0x5C
30 #define CURR_POWER_MODE 0x80
31 #define PMU_EVENT_STATUS 0x88
32 #define PMU_INT_STATUS 0x8C
34 /* sw encourage cfg */
35 #define SW_MODE_ENCOURAGE_EN_LO 0x05
36 #define SW_MODE_ENCOURAGE_EN_HI 0x50
37 #define SW_MODE_ENCOURAGE_DIS_LO 0x0A
38 #define SW_MODE_ENCOURAGE_DIS_HI 0xA0
39 #define SW_MODE_ENCOURAGE_ON 0xFF
42 #define PMU_INT_SEQ_DONE BIT(0)
43 #define PMU_INT_HW_REQ BIT(1)
44 #define PMU_INT_SW_FAIL GENMASK(3, 2)
45 #define PMU_INT_HW_FAIL GENMASK(5, 4)
46 #define PMU_INT_PCH_FAIL GENMASK(8, 6)
47 #define PMU_INT_FAIL_MASK (PMU_INT_SW_FAIL | \
50 #define PMU_INT_ALL_MASK (PMU_INT_SEQ_DONE | \
55 #define TIMEOUT_US 100000
57 struct jh7110_power_dev {
58 struct generic_pm_domain genpd;
59 struct jh7110_pmu *power;
68 struct jh7110_power_dev *dev;
69 struct genpd_onecell_data genpd_data;
70 struct generic_pm_domain **genpd;
73 struct jh7110_pmu_data {
74 const char * const name;
79 static void __iomem *pmu_base;
81 static inline void pmu_writel(u32 val, u32 offset)
83 writel(val, pmu_base + offset);
86 void starfive_pmu_hw_event_turn_off_mask(u32 mask)
88 pmu_writel(mask, HW_EVENT_TURN_OFF_MASK);
90 EXPORT_SYMBOL(starfive_pmu_hw_event_turn_off_mask);
92 static int jh7110_pmu_get_state(struct jh7110_power_dev *pmd, bool *is_on)
94 struct jh7110_pmu *pmu = pmd->power;
101 *is_on = __raw_readl(pmu->base + CURR_POWER_MODE) & pmd->mask;
106 static int jh7110_pmu_set_state(struct jh7110_power_dev *pmd, bool on)
108 struct jh7110_pmu *pmu = pmd->power;
112 uint32_t encourage_lo;
113 uint32_t encourage_hi;
120 ret = jh7110_pmu_get_state(pmd, &is_on);
122 dev_info(pmu->pdev, "unable to get current state for %s\n",
125 dev_info(pmu->pdev, "pm domain [%s] is already %sable status.\n",
126 pmd->genpd.name, on ? "en" : "dis");
130 spin_lock_irqsave(&pmu->lock, flags);
133 mode = SW_TURN_ON_POWER_MODE;
134 encourage_lo = SW_MODE_ENCOURAGE_EN_LO;
135 encourage_hi = SW_MODE_ENCOURAGE_EN_HI;
137 mode = SW_TURN_OFF_POWER_MODE;
138 encourage_lo = SW_MODE_ENCOURAGE_DIS_LO;
139 encourage_hi = SW_MODE_ENCOURAGE_DIS_HI;
142 __raw_writel(pmd->mask, pmu->base + mode);
144 /* write SW_ENCOURAGE to make the configuration take effect */
145 __raw_writel(SW_MODE_ENCOURAGE_ON, pmu->base + SW_ENCOURAGE);
146 __raw_writel(encourage_lo, pmu->base + SW_ENCOURAGE);
147 __raw_writel(encourage_hi, pmu->base + SW_ENCOURAGE);
149 spin_unlock_irqrestore(&pmu->lock, flags);
152 ret = readl_poll_timeout_atomic(pmu->base + CURR_POWER_MODE, val,
153 val & pmd->mask, DELAY_US,
156 dev_err(pmu->pdev, "%s power_on failed", pmd->genpd.name);
160 ret = readl_poll_timeout_atomic(pmu->base + CURR_POWER_MODE, val,
161 !(val & pmd->mask), DELAY_US,
164 dev_err(pmu->pdev, "%s power_off failed", pmd->genpd.name);
172 static int jh7110_pmu_on(struct generic_pm_domain *genpd)
174 struct jh7110_power_dev *pmd = container_of(genpd,
175 struct jh7110_power_dev, genpd);
177 return jh7110_pmu_set_state(pmd, true);
180 static int jh7110_pmu_off(struct generic_pm_domain *genpd)
182 struct jh7110_power_dev *pmd = container_of(genpd,
183 struct jh7110_power_dev, genpd);
185 return jh7110_pmu_set_state(pmd, false);
188 static void starfive_pmu_int_enable(struct jh7110_pmu *pmu, u32 mask, bool enable)
190 u32 val = __raw_readl(pmu->base + PMU_INT_MASK);
197 __raw_writel(val, pmu->base + PMU_INT_MASK);
200 static irqreturn_t starfive_pmu_interrupt(int irq, void *data)
202 struct jh7110_pmu *pmu = data;
206 spin_lock_irqsave(&pmu->lock, flags);
207 val = __raw_readl(pmu->base + PMU_INT_STATUS);
209 if (val & PMU_INT_SEQ_DONE)
210 dev_dbg(pmu->pdev, "sequence done.\n");
211 if (val & PMU_INT_HW_REQ)
212 dev_dbg(pmu->pdev, "hardware encourage requestion.\n");
213 if (val & PMU_INT_SW_FAIL)
214 dev_err(pmu->pdev, "software encourage fail.\n");
215 if (val & PMU_INT_HW_FAIL)
216 dev_err(pmu->pdev, "hardware encourage fail.\n");
217 if (val & PMU_INT_PCH_FAIL)
218 dev_err(pmu->pdev, "p-channel fail event.\n");
220 /* clear interrupts */
221 __raw_writel(val, pmu->base + PMU_INT_STATUS);
222 __raw_writel(val, pmu->base + PMU_EVENT_STATUS);
224 spin_unlock_irqrestore(&pmu->lock, flags);
229 static int jh7110_pmu_probe(struct platform_device *pdev)
231 struct device *dev = &pdev->dev;
232 struct device_node *np = dev->of_node;
233 struct resource *res;
234 const struct jh7110_pmu_data *entry, *table;
235 struct jh7110_pmu *pmu;
240 pmu = devm_kzalloc(dev, sizeof(*pmu), GFP_KERNEL);
244 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
245 pmu_base = pmu->base = devm_ioremap_resource(&pdev->dev, res);
246 if (IS_ERR(pmu->base))
247 return PTR_ERR(pmu->base);
249 /* initialize pmu interrupt */
250 pmu->irq = platform_get_irq(pdev, 0);
254 ret = devm_request_irq(dev, pmu->irq, starfive_pmu_interrupt,
257 dev_err(dev, "request irq failed.\n");
259 table = of_device_get_match_data(dev);
264 pmu->genpd_data.num_domains = 0;
266 for (entry = table; entry->name; entry++) {
267 max_bit = max(max_bit, entry->bit);
274 pmu->genpd_data.num_domains = max_bit + 1;
276 pmu->dev = devm_kcalloc(dev, pmu->genpd_data.num_domains,
277 sizeof(struct jh7110_power_dev),
282 pmu->genpd = devm_kcalloc(dev, pmu->genpd_data.num_domains,
283 sizeof(struct generic_pm_domain *),
288 pmu->genpd_data.domains = pmu->genpd;
291 for (entry = table; entry->name; entry++) {
292 struct jh7110_power_dev *pmd = &pmu->dev[i];
296 pmd->mask = BIT(entry->bit);
297 pmd->genpd.name = entry->name;
298 pmd->genpd.flags = entry->flags;
300 ret = jh7110_pmu_get_state(pmd, &is_on);
302 dev_warn(dev, "unable to get current state for %s\n",
305 pmd->genpd.power_on = jh7110_pmu_on;
306 pmd->genpd.power_off = jh7110_pmu_off;
308 pm_genpd_init(&pmd->genpd, NULL, !is_on);
309 pmu->genpd[entry->bit] = &pmd->genpd;
314 spin_lock_init(&pmu->lock);
315 starfive_pmu_int_enable(pmu, PMU_INT_ALL_MASK & ~PMU_INT_PCH_FAIL, true);
317 ret = of_genpd_add_provider_onecell(np, &pmu->genpd_data);
319 dev_err(dev, "failed to register genpd driver: %d\n", ret);
323 dev_info(dev, "registered %u power domains\n", i);
328 static const struct jh7110_pmu_data jh7110_power_domains[] = {
331 .bit = JH7110_PD_SYSTOP,
332 .flags = GENPD_FLAG_ALWAYS_ON,
335 .bit = JH7110_PD_CPU,
336 .flags = GENPD_FLAG_ALWAYS_ON,
339 .bit = JH7110_PD_GPUA,
342 .bit = JH7110_PD_VDEC,
345 .bit = JH7110_PD_VOUT,
348 .bit = JH7110_PD_ISP,
351 .bit = JH7110_PD_VENC,
354 .bit = JH7110_PD_GPUB,
360 static const struct of_device_id jh7110_pmu_of_match[] = {
362 .compatible = "starfive,jh7110-pmu",
363 .data = &jh7110_power_domains,
369 static struct platform_driver jh7110_pmu_driver = {
371 .name = "jh7110-pmu",
372 .of_match_table = jh7110_pmu_of_match,
374 .probe = jh7110_pmu_probe,
376 builtin_platform_driver(jh7110_pmu_driver);
378 MODULE_AUTHOR("Walker Chen <walker.chen@linux.starfivetech.com>");
379 MODULE_DESCRIPTION("Starfive JH7110 Power Domain Driver");
380 MODULE_LICENSE("GPL");