Lines Matching +full:mpm +full:- +full:pin +full:- +full:map
1 // SPDX-License-Identifier: GPL-2.0-only
4 * Copyright (c) 2010-2020, The Linux Foundation. All rights reserved.
26 * This is the driver for Qualcomm MPM (MSM Power Manager) interrupt controller,
28 * Sitting in always-on domain, MPM monitors the wakeup interrupts when SoC is
30 * doesn't directly access physical MPM registers though. Instead, the access
37 * ownership and dump vMPM into physical MPM registers. On wakeup, AP is woken
38 * up by a MPM pin/interrupt, and RPM will copy STATUS registers into vMPM.
41 * vMPM register map:
44 * +--------------------------------+
46 * +--------------------------------+
48 * +--------------------------------+
50 * +--------------------------------+
52 * +--------------------------------+
54 * +--------------------------------+
56 * +--------------------------------+
58 * +--------------------------------+
60 * +--------------------------------+
72 /* MPM pin map to GIC hwirq */
74 int pin; member
93 unsigned int offset = (reg * priv->reg_stride + index + 2) * 4; in qcom_mpm_read()
95 return readl_relaxed(priv->base + offset); in qcom_mpm_read()
101 unsigned int offset = (reg * priv->reg_stride + index + 2) * 4; in qcom_mpm_write()
103 writel_relaxed(val, priv->base + offset); in qcom_mpm_write()
111 struct qcom_mpm_priv *priv = d->chip_data; in qcom_mpm_enable_irq()
112 int pin = d->hwirq; in qcom_mpm_enable_irq() local
113 unsigned int index = pin / 32; in qcom_mpm_enable_irq()
114 unsigned int shift = pin % 32; in qcom_mpm_enable_irq()
117 raw_spin_lock_irqsave(&priv->lock, flags); in qcom_mpm_enable_irq()
123 raw_spin_unlock_irqrestore(&priv->lock, flags); in qcom_mpm_enable_irq()
130 if (d->parent_data) in qcom_mpm_mask()
138 if (d->parent_data) in qcom_mpm_unmask()
147 raw_spin_lock_irqsave(&priv->lock, flags); in mpm_set_type()
153 raw_spin_unlock_irqrestore(&priv->lock, flags); in mpm_set_type()
158 struct qcom_mpm_priv *priv = d->chip_data; in qcom_mpm_set_type()
159 int pin = d->hwirq; in qcom_mpm_set_type() local
160 unsigned int index = pin / 32; in qcom_mpm_set_type()
161 unsigned int shift = pin % 32; in qcom_mpm_set_type()
178 if (!d->parent_data) in qcom_mpm_set_type()
191 .name = "mpm",
202 static struct mpm_gic_map *get_mpm_gic_map(struct qcom_mpm_priv *priv, int pin) in get_mpm_gic_map() argument
204 struct mpm_gic_map *maps = priv->maps; in get_mpm_gic_map()
207 for (i = 0; i < priv->map_cnt; i++) { in get_mpm_gic_map()
208 if (maps[i].pin == pin) in get_mpm_gic_map()
218 struct qcom_mpm_priv *priv = domain->host_data; in qcom_mpm_alloc()
221 struct mpm_gic_map *map; in qcom_mpm_alloc() local
222 irq_hw_number_t pin; in qcom_mpm_alloc() local
226 ret = irq_domain_translate_twocell(domain, fwspec, &pin, &type); in qcom_mpm_alloc()
230 ret = irq_domain_set_hwirq_and_chip(domain, virq, pin, in qcom_mpm_alloc()
235 map = get_mpm_gic_map(priv, pin); in qcom_mpm_alloc()
236 if (map == NULL) in qcom_mpm_alloc()
237 return irq_domain_disconnect_hierarchy(domain->parent, virq); in qcom_mpm_alloc()
245 parent_fwspec.fwnode = domain->parent->fwnode; in qcom_mpm_alloc()
248 parent_fwspec.param[1] = map->hwirq; in qcom_mpm_alloc()
270 for (i = 0; i < priv->reg_stride; i++) { in qcom_mpm_handler()
271 raw_spin_lock_irqsave(&priv->lock, flags); in qcom_mpm_handler()
275 raw_spin_unlock_irqrestore(&priv->lock, flags); in qcom_mpm_handler()
278 unsigned int pin = 32 * i + j; in qcom_mpm_handler() local
279 struct irq_desc *desc = irq_resolve_mapping(priv->domain, pin); in qcom_mpm_handler()
280 struct irq_data *d = &desc->irq_data; in qcom_mpm_handler()
283 irq_set_irqchip_state(d->irq, in qcom_mpm_handler()
298 for (i = 0; i < priv->reg_stride; i++) in mpm_pd_power_off()
302 ret = mbox_send_message(priv->mbox_chan, NULL); in mpm_pd_power_off()
323 struct device *dev = &pdev->dev; in qcom_mpm_init()
335 return -ENOMEM; in qcom_mpm_init()
337 ret = of_property_read_u32(np, "qcom,mpm-pin-count", &pin_cnt); in qcom_mpm_init()
339 dev_err(dev, "failed to read qcom,mpm-pin-count: %d\n", ret); in qcom_mpm_init()
343 priv->reg_stride = DIV_ROUND_UP(pin_cnt, 32); in qcom_mpm_init()
345 ret = of_property_count_u32_elems(np, "qcom,mpm-pin-map"); in qcom_mpm_init()
347 dev_err(dev, "failed to read qcom,mpm-pin-map: %d\n", ret); in qcom_mpm_init()
352 dev_err(dev, "invalid qcom,mpm-pin-map\n"); in qcom_mpm_init()
353 return -EINVAL; in qcom_mpm_init()
356 priv->map_cnt = ret / 2; in qcom_mpm_init()
357 priv->maps = devm_kcalloc(dev, priv->map_cnt, sizeof(*priv->maps), in qcom_mpm_init()
359 if (!priv->maps) in qcom_mpm_init()
360 return -ENOMEM; in qcom_mpm_init()
362 for (i = 0; i < priv->map_cnt; i++) { in qcom_mpm_init()
363 u32 pin, hwirq; in qcom_mpm_init() local
365 of_property_read_u32_index(np, "qcom,mpm-pin-map", i * 2, &pin); in qcom_mpm_init()
366 of_property_read_u32_index(np, "qcom,mpm-pin-map", i * 2 + 1, &hwirq); in qcom_mpm_init()
368 if (gic_hwirq_is_mapped(priv->maps, i, hwirq)) { in qcom_mpm_init()
369 dev_warn(dev, "failed to map pin %d as GIC hwirq %d is already mapped\n", in qcom_mpm_init()
370 pin, hwirq); in qcom_mpm_init()
374 priv->maps[i].pin = pin; in qcom_mpm_init()
375 priv->maps[i].hwirq = hwirq; in qcom_mpm_init()
378 raw_spin_lock_init(&priv->lock); in qcom_mpm_init()
381 msgram_np = of_parse_phandle(np, "qcom,rpm-msg-ram", 0); in qcom_mpm_init()
390 priv->base = devm_ioremap(dev, res.start, resource_size(&res)); in qcom_mpm_init()
392 if (!priv->base) in qcom_mpm_init()
393 return -ENOMEM; in qcom_mpm_init()
396 priv->base = devm_platform_ioremap_resource(pdev, 0); in qcom_mpm_init()
397 if (IS_ERR(priv->base)) in qcom_mpm_init()
398 return PTR_ERR(priv->base); in qcom_mpm_init()
401 for (i = 0; i < priv->reg_stride; i++) { in qcom_mpm_init()
413 genpd = &priv->genpd; in qcom_mpm_init()
414 genpd->flags = GENPD_FLAG_IRQ_SAFE; in qcom_mpm_init()
415 genpd->power_off = mpm_pd_power_off; in qcom_mpm_init()
417 genpd->name = devm_kasprintf(dev, GFP_KERNEL, "%s", dev_name(dev)); in qcom_mpm_init()
418 if (!genpd->name) in qcom_mpm_init()
419 return -ENOMEM; in qcom_mpm_init()
433 priv->mbox_client.dev = dev; in qcom_mpm_init()
434 priv->mbox_chan = mbox_request_channel(&priv->mbox_client, 0); in qcom_mpm_init()
435 if (IS_ERR(priv->mbox_chan)) { in qcom_mpm_init()
436 ret = PTR_ERR(priv->mbox_chan); in qcom_mpm_init()
443 dev_err(dev, "failed to find MPM parent domain\n"); in qcom_mpm_init()
444 ret = -ENXIO; in qcom_mpm_init()
448 priv->domain = irq_domain_create_hierarchy(parent_domain, in qcom_mpm_init()
451 if (!priv->domain) { in qcom_mpm_init()
452 dev_err(dev, "failed to create MPM domain\n"); in qcom_mpm_init()
453 ret = -ENOMEM; in qcom_mpm_init()
457 irq_domain_update_bus_token(priv->domain, DOMAIN_BUS_WAKEUP); in qcom_mpm_init()
469 irq_domain_remove(priv->domain); in qcom_mpm_init()
471 mbox_free_channel(priv->mbox_chan); in qcom_mpm_init()
478 IRQCHIP_MATCH("qcom,mpm", qcom_mpm_init)