Lines Matching +full:smem +full:- +full:states
1 // SPDX-License-Identifier: GPL-2.0-only
4 * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
14 #include <linux/soc/qcom/smem.h>
26 * read-write, while the rest should be considered read-only.
33 * The subscription matrix is laid out in entry-major order:
62 * struct qcom_smsm - smsm driver context
70 * @state: smem state handle
71 * @lock: spinlock for read-modify-write of the outgoing state
94 * struct smsm_entry - per remote processor entry context
95 * @smsm: back-reference to driver context
119 * struct smsm_host - representation of a remote host
131 * smsm_update_bits() - change bit in outgoing entry and inform subscribers
149 spin_lock_irqsave(&smsm->lock, flags); in smsm_update_bits()
152 val = orig = readl(smsm->local_state); in smsm_update_bits()
159 spin_unlock_irqrestore(&smsm->lock, flags); in smsm_update_bits()
164 writel(val, smsm->local_state); in smsm_update_bits()
165 spin_unlock_irqrestore(&smsm->lock, flags); in smsm_update_bits()
171 for (host = 0; host < smsm->num_hosts; host++) { in smsm_update_bits()
172 hostp = &smsm->hosts[host]; in smsm_update_bits()
174 val = readl(smsm->subscription + host); in smsm_update_bits()
175 if (val & changes && hostp->ipc_regmap) { in smsm_update_bits()
176 regmap_write(hostp->ipc_regmap, in smsm_update_bits()
177 hostp->ipc_offset, in smsm_update_bits()
178 BIT(hostp->ipc_bit)); in smsm_update_bits()
191 * smsm_intr() - cascading IRQ handler for SMSM
206 val = readl(entry->remote_state); in smsm_intr()
207 changed = val ^ entry->last_value; in smsm_intr()
208 entry->last_value = val; in smsm_intr()
210 for_each_set_bit(i, entry->irq_enabled, 32) { in smsm_intr()
215 if (test_bit(i, entry->irq_rising)) { in smsm_intr()
216 irq_pin = irq_find_mapping(entry->domain, i); in smsm_intr()
220 if (test_bit(i, entry->irq_falling)) { in smsm_intr()
221 irq_pin = irq_find_mapping(entry->domain, i); in smsm_intr()
231 * smsm_mask_irq() - un-subscribe from cascades of IRQs of a certain staus bit
234 * This un-subscribes the local CPU from interrupts upon changes to the defines
241 struct qcom_smsm *smsm = entry->smsm; in smsm_mask_irq()
244 if (entry->subscription) { in smsm_mask_irq()
245 val = readl(entry->subscription + smsm->local_host); in smsm_mask_irq()
247 writel(val, entry->subscription + smsm->local_host); in smsm_mask_irq()
250 clear_bit(irq, entry->irq_enabled); in smsm_mask_irq()
254 * smsm_unmask_irq() - subscribe to cascades of IRQs of a certain status bit
266 struct qcom_smsm *smsm = entry->smsm; in smsm_unmask_irq()
269 set_bit(irq, entry->irq_enabled); in smsm_unmask_irq()
271 if (entry->subscription) { in smsm_unmask_irq()
272 val = readl(entry->subscription + smsm->local_host); in smsm_unmask_irq()
274 writel(val, entry->subscription + smsm->local_host); in smsm_unmask_irq()
279 * smsm_set_irq_type() - updates the requested IRQ type for the cascading
289 return -EINVAL; in smsm_set_irq_type()
292 set_bit(irq, entry->irq_rising); in smsm_set_irq_type()
294 clear_bit(irq, entry->irq_rising); in smsm_set_irq_type()
297 set_bit(irq, entry->irq_falling); in smsm_set_irq_type()
299 clear_bit(irq, entry->irq_falling); in smsm_set_irq_type()
312 * smsm_irq_map() - sets up a mapping for a cascaded IRQ
321 struct smsm_entry *entry = d->host_data; in smsm_irq_map()
336 * smsm_parse_ipc() - parses a qcom,ipc-%d device tree property
341 * outgoing interrupts to a remote host - identified by @host_id.
346 struct device_node *node = smsm->dev->of_node; in smsm_parse_ipc()
347 struct smsm_host *host = &smsm->hosts[host_id]; in smsm_parse_ipc()
351 snprintf(key, sizeof(key), "qcom,ipc-%d", host_id); in smsm_parse_ipc()
356 host->ipc_regmap = syscon_node_to_regmap(syscon); in smsm_parse_ipc()
357 if (IS_ERR(host->ipc_regmap)) in smsm_parse_ipc()
358 return PTR_ERR(host->ipc_regmap); in smsm_parse_ipc()
360 ret = of_property_read_u32_index(node, key, 1, &host->ipc_offset); in smsm_parse_ipc()
362 dev_err(smsm->dev, "no offset in %s\n", key); in smsm_parse_ipc()
363 return -EINVAL; in smsm_parse_ipc()
366 ret = of_property_read_u32_index(node, key, 2, &host->ipc_bit); in smsm_parse_ipc()
368 dev_err(smsm->dev, "no bit in %s\n", key); in smsm_parse_ipc()
369 return -EINVAL; in smsm_parse_ipc()
376 * smsm_inbound_entry() - parse DT and set up an entry representing a remote system
390 dev_err(smsm->dev, "failed to parse smsm interrupt\n"); in smsm_inbound_entry()
391 return -EINVAL; in smsm_inbound_entry()
394 ret = devm_request_threaded_irq(smsm->dev, irq, in smsm_inbound_entry()
399 dev_err(smsm->dev, "failed to request interrupt\n"); in smsm_inbound_entry()
403 entry->domain = irq_domain_add_linear(node, 32, &smsm_irq_ops, entry); in smsm_inbound_entry()
404 if (!entry->domain) { in smsm_inbound_entry()
405 dev_err(smsm->dev, "failed to add irq_domain\n"); in smsm_inbound_entry()
406 return -ENOMEM; in smsm_inbound_entry()
413 * smsm_get_size_info() - parse the optional memory segment for sizes
434 if (IS_ERR(info) && PTR_ERR(info) != -ENOENT) { in smsm_get_size_info()
435 if (PTR_ERR(info) != -EPROBE_DEFER) in smsm_get_size_info()
436 dev_err(smsm->dev, "unable to retrieve smsm size info\n"); in smsm_get_size_info()
439 dev_warn(smsm->dev, "no smsm size info, using defaults\n"); in smsm_get_size_info()
440 smsm->num_entries = SMSM_DEFAULT_NUM_ENTRIES; in smsm_get_size_info()
441 smsm->num_hosts = SMSM_DEFAULT_NUM_HOSTS; in smsm_get_size_info()
445 smsm->num_entries = info->num_entries; in smsm_get_size_info()
446 smsm->num_hosts = info->num_hosts; in smsm_get_size_info()
448 dev_dbg(smsm->dev, in smsm_get_size_info()
450 smsm->num_entries, smsm->num_hosts); in smsm_get_size_info()
463 u32 *states; in qcom_smsm_probe() local
467 smsm = devm_kzalloc(&pdev->dev, sizeof(*smsm), GFP_KERNEL); in qcom_smsm_probe()
469 return -ENOMEM; in qcom_smsm_probe()
470 smsm->dev = &pdev->dev; in qcom_smsm_probe()
471 spin_lock_init(&smsm->lock); in qcom_smsm_probe()
477 smsm->entries = devm_kcalloc(&pdev->dev, in qcom_smsm_probe()
478 smsm->num_entries, in qcom_smsm_probe()
481 if (!smsm->entries) in qcom_smsm_probe()
482 return -ENOMEM; in qcom_smsm_probe()
484 smsm->hosts = devm_kcalloc(&pdev->dev, in qcom_smsm_probe()
485 smsm->num_hosts, in qcom_smsm_probe()
488 if (!smsm->hosts) in qcom_smsm_probe()
489 return -ENOMEM; in qcom_smsm_probe()
491 for_each_child_of_node(pdev->dev.of_node, local_node) { in qcom_smsm_probe()
492 if (of_find_property(local_node, "#qcom,smem-state-cells", NULL)) in qcom_smsm_probe()
496 dev_err(&pdev->dev, "no state entry\n"); in qcom_smsm_probe()
497 return -EINVAL; in qcom_smsm_probe()
500 of_property_read_u32(pdev->dev.of_node, in qcom_smsm_probe()
501 "qcom,local-host", in qcom_smsm_probe()
502 &smsm->local_host); in qcom_smsm_probe()
505 for (id = 0; id < smsm->num_hosts; id++) { in qcom_smsm_probe()
513 smsm->num_entries * sizeof(u32)); in qcom_smsm_probe()
514 if (ret < 0 && ret != -EEXIST) { in qcom_smsm_probe()
515 dev_err(&pdev->dev, "unable to allocate shared state entry\n"); in qcom_smsm_probe()
519 states = qcom_smem_get(QCOM_SMEM_HOST_ANY, SMEM_SMSM_SHARED_STATE, NULL); in qcom_smsm_probe()
520 if (IS_ERR(states)) { in qcom_smsm_probe()
521 dev_err(&pdev->dev, "Unable to acquire shared state entry\n"); in qcom_smsm_probe()
522 return PTR_ERR(states); in qcom_smsm_probe()
526 size = smsm->num_entries * smsm->num_hosts * sizeof(u32); in qcom_smsm_probe()
528 if (ret < 0 && ret != -EEXIST) { in qcom_smsm_probe()
529 dev_err(&pdev->dev, "unable to allocate smsm interrupt mask\n"); in qcom_smsm_probe()
535 dev_err(&pdev->dev, "unable to acquire shared memory interrupt mask\n"); in qcom_smsm_probe()
540 smsm->local_state = states + smsm->local_host; in qcom_smsm_probe()
541 smsm->subscription = intr_mask + smsm->local_host * smsm->num_hosts; in qcom_smsm_probe()
544 smsm->state = qcom_smem_state_register(local_node, &smsm_state_ops, smsm); in qcom_smsm_probe()
545 if (IS_ERR(smsm->state)) { in qcom_smsm_probe()
546 dev_err(smsm->dev, "failed to register qcom_smem_state\n"); in qcom_smsm_probe()
547 return PTR_ERR(smsm->state); in qcom_smsm_probe()
551 for_each_available_child_of_node(pdev->dev.of_node, node) { in qcom_smsm_probe()
552 if (!of_property_read_bool(node, "interrupt-controller")) in qcom_smsm_probe()
556 if (ret || id >= smsm->num_entries) { in qcom_smsm_probe()
557 dev_err(&pdev->dev, "invalid reg of entry\n"); in qcom_smsm_probe()
559 ret = -EINVAL; in qcom_smsm_probe()
562 entry = &smsm->entries[id]; in qcom_smsm_probe()
564 entry->smsm = smsm; in qcom_smsm_probe()
565 entry->remote_state = states + id; in qcom_smsm_probe()
568 entry->subscription = intr_mask + id * smsm->num_hosts; in qcom_smsm_probe()
569 writel(0, entry->subscription + smsm->local_host); in qcom_smsm_probe()
581 for (id = 0; id < smsm->num_entries; id++) in qcom_smsm_probe()
582 if (smsm->entries[id].domain) in qcom_smsm_probe()
583 irq_domain_remove(smsm->entries[id].domain); in qcom_smsm_probe()
585 qcom_smem_state_unregister(smsm->state); in qcom_smsm_probe()
595 for (id = 0; id < smsm->num_entries; id++) in qcom_smsm_remove()
596 if (smsm->entries[id].domain) in qcom_smsm_remove()
597 irq_domain_remove(smsm->entries[id].domain); in qcom_smsm_remove()
599 qcom_smem_state_unregister(smsm->state); in qcom_smsm_remove()
614 .name = "qcom-smsm",