Dirk Brandewie | 002c53b | 2015-09-29 08:42:22 -0700 | [diff] [blame] | 1 | /* |
Navinkumar Balabakthan | a8490c3 | 2023-08-24 06:03:17 +0000 | [diff] [blame] | 2 | * Copyright (c) 2015 - 2023 Intel Corporation. |
Dirk Brandewie | 002c53b | 2015-09-29 08:42:22 -0700 | [diff] [blame] | 3 | * |
David B. Kinder | ac74d8b | 2017-01-18 17:01:01 -0800 | [diff] [blame] | 4 | * SPDX-License-Identifier: Apache-2.0 |
Dirk Brandewie | 002c53b | 2015-09-29 08:42:22 -0700 | [diff] [blame] | 5 | */ |
| 6 | |
Kumar Gala | 67d42d6 | 2020-03-25 12:05:44 -0500 | [diff] [blame] | 7 | #define DT_DRV_COMPAT shared_irq |
| 8 | |
Andre Guedes | 7c956d2 | 2016-03-09 14:38:02 -0300 | [diff] [blame] | 9 | #include <errno.h> |
| 10 | |
Gerard Marull-Paretas | fb60aab | 2022-05-06 10:25:46 +0200 | [diff] [blame] | 11 | #include <zephyr/kernel.h> |
| 12 | #include <zephyr/device.h> |
| 13 | #include <zephyr/shared_irq.h> |
| 14 | #include <zephyr/init.h> |
| 15 | #include <zephyr/sys/sys_io.h> |
Gerard Marull-Paretas | 178bdc4 | 2022-10-17 10:24:11 +0200 | [diff] [blame] | 16 | #include <zephyr/irq.h> |
Dirk Brandewie | 002c53b | 2015-09-29 08:42:22 -0700 | [diff] [blame] | 17 | |
Daniel Leung | 8effb4f | 2015-12-10 09:52:56 -0800 | [diff] [blame] | 18 | #ifdef CONFIG_IOAPIC |
Gerard Marull-Paretas | fb60aab | 2022-05-06 10:25:46 +0200 | [diff] [blame] | 19 | #include <zephyr/drivers/interrupt_controller/ioapic.h> |
Daniel Leung | 8effb4f | 2015-12-10 09:52:56 -0800 | [diff] [blame] | 20 | #endif |
| 21 | |
Henrik Brix Andersen | e8ffafa | 2021-04-10 22:18:15 +0200 | [diff] [blame] | 22 | typedef void (*shared_irq_config_irq_t)(void); |
| 23 | |
| 24 | struct shared_irq_config { |
| 25 | uint32_t irq_num; |
| 26 | shared_irq_config_irq_t config; |
| 27 | uint32_t client_count; |
| 28 | }; |
| 29 | |
| 30 | struct shared_irq_client { |
| 31 | const struct device *isr_dev; |
| 32 | isr_t isr_func; |
| 33 | uint32_t enabled; |
| 34 | }; |
| 35 | |
| 36 | struct shared_irq_runtime { |
Thomas Stranger | dedd444 | 2021-03-28 18:07:56 +0200 | [diff] [blame] | 37 | struct shared_irq_client *const client; |
Henrik Brix Andersen | e8ffafa | 2021-04-10 22:18:15 +0200 | [diff] [blame] | 38 | }; |
| 39 | |
Dirk Brandewie | 002c53b | 2015-09-29 08:42:22 -0700 | [diff] [blame] | 40 | /** |
| 41 | * @brief Register a device ISR |
| 42 | * @param dev Pointer to device structure for SHARED_IRQ driver instance. |
| 43 | * @param isr_func Pointer to the ISR function for the device. |
| 44 | * @param isr_dev Pointer to the device that will service the interrupt. |
| 45 | */ |
Tomasz Bursztyka | e18fcbb | 2020-04-30 20:33:38 +0200 | [diff] [blame] | 46 | static int isr_register(const struct device *dev, isr_t isr_func, |
| 47 | const struct device *isr_dev) |
Dirk Brandewie | 002c53b | 2015-09-29 08:42:22 -0700 | [diff] [blame] | 48 | { |
Tomasz Bursztyka | 98d9b01 | 2020-05-28 21:23:02 +0200 | [diff] [blame] | 49 | struct shared_irq_runtime *clients = dev->data; |
Tomasz Bursztyka | af6140c | 2020-05-28 20:44:16 +0200 | [diff] [blame] | 50 | const struct shared_irq_config *config = dev->config; |
Kumar Gala | a1b77fd | 2020-05-27 11:26:57 -0500 | [diff] [blame] | 51 | uint32_t i; |
Dirk Brandewie | 002c53b | 2015-09-29 08:42:22 -0700 | [diff] [blame] | 52 | |
Patrik Flykt | 8ff96b5 | 2018-11-29 11:12:22 -0800 | [diff] [blame] | 53 | for (i = 0U; i < config->client_count; i++) { |
Dirk Brandewie | 002c53b | 2015-09-29 08:42:22 -0700 | [diff] [blame] | 54 | if (!clients->client[i].isr_dev) { |
| 55 | clients->client[i].isr_dev = isr_dev; |
| 56 | clients->client[i].isr_func = isr_func; |
Andre Guedes | 024cfe7 | 2016-03-09 14:01:20 -0300 | [diff] [blame] | 57 | return 0; |
Dirk Brandewie | 002c53b | 2015-09-29 08:42:22 -0700 | [diff] [blame] | 58 | } |
| 59 | } |
Andre Guedes | 7c956d2 | 2016-03-09 14:38:02 -0300 | [diff] [blame] | 60 | return -EIO; |
Dirk Brandewie | 002c53b | 2015-09-29 08:42:22 -0700 | [diff] [blame] | 61 | } |
| 62 | |
| 63 | /** |
| 64 | * @brief Enable ISR for device |
| 65 | * @param dev Pointer to device structure for SHARED_IRQ driver instance. |
| 66 | * @param isr_dev Pointer to the device that will service the interrupt. |
| 67 | */ |
Tomasz Bursztyka | e18fcbb | 2020-04-30 20:33:38 +0200 | [diff] [blame] | 68 | static inline int enable(const struct device *dev, |
| 69 | const struct device *isr_dev) |
Dirk Brandewie | 002c53b | 2015-09-29 08:42:22 -0700 | [diff] [blame] | 70 | { |
Tomasz Bursztyka | 98d9b01 | 2020-05-28 21:23:02 +0200 | [diff] [blame] | 71 | struct shared_irq_runtime *clients = dev->data; |
Tomasz Bursztyka | af6140c | 2020-05-28 20:44:16 +0200 | [diff] [blame] | 72 | const struct shared_irq_config *config = dev->config; |
Kumar Gala | a1b77fd | 2020-05-27 11:26:57 -0500 | [diff] [blame] | 73 | uint32_t i; |
Dirk Brandewie | 002c53b | 2015-09-29 08:42:22 -0700 | [diff] [blame] | 74 | |
Patrik Flykt | 8ff96b5 | 2018-11-29 11:12:22 -0800 | [diff] [blame] | 75 | for (i = 0U; i < config->client_count; i++) { |
Dirk Brandewie | 002c53b | 2015-09-29 08:42:22 -0700 | [diff] [blame] | 76 | if (clients->client[i].isr_dev == isr_dev) { |
Patrik Flykt | 24d7143 | 2019-03-26 19:57:45 -0600 | [diff] [blame] | 77 | clients->client[i].enabled = 1U; |
Dirk Brandewie | 002c53b | 2015-09-29 08:42:22 -0700 | [diff] [blame] | 78 | irq_enable(config->irq_num); |
Andre Guedes | 024cfe7 | 2016-03-09 14:01:20 -0300 | [diff] [blame] | 79 | return 0; |
Dirk Brandewie | 002c53b | 2015-09-29 08:42:22 -0700 | [diff] [blame] | 80 | } |
| 81 | } |
Andre Guedes | 7c956d2 | 2016-03-09 14:38:02 -0300 | [diff] [blame] | 82 | return -EIO; |
Dirk Brandewie | 002c53b | 2015-09-29 08:42:22 -0700 | [diff] [blame] | 83 | } |
| 84 | |
| 85 | static int last_enabled_isr(struct shared_irq_runtime *clients, int count) |
| 86 | { |
Kumar Gala | a1b77fd | 2020-05-27 11:26:57 -0500 | [diff] [blame] | 87 | uint32_t i; |
Dirk Brandewie | 002c53b | 2015-09-29 08:42:22 -0700 | [diff] [blame] | 88 | |
Patrik Flykt | 8ff96b5 | 2018-11-29 11:12:22 -0800 | [diff] [blame] | 89 | for (i = 0U; i < count; i++) { |
Dirk Brandewie | 002c53b | 2015-09-29 08:42:22 -0700 | [diff] [blame] | 90 | if (clients->client[i].enabled) { |
| 91 | return 0; |
| 92 | } |
| 93 | } |
| 94 | return 1; |
| 95 | } |
| 96 | /** |
| 97 | * @brief Disable ISR for device |
| 98 | * @param dev Pointer to device structure for SHARED_IRQ driver instance. |
| 99 | * @param isr_dev Pointer to the device that will service the interrupt. |
| 100 | */ |
Tomasz Bursztyka | e18fcbb | 2020-04-30 20:33:38 +0200 | [diff] [blame] | 101 | static inline int disable(const struct device *dev, |
| 102 | const struct device *isr_dev) |
Dirk Brandewie | 002c53b | 2015-09-29 08:42:22 -0700 | [diff] [blame] | 103 | { |
Tomasz Bursztyka | 98d9b01 | 2020-05-28 21:23:02 +0200 | [diff] [blame] | 104 | struct shared_irq_runtime *clients = dev->data; |
Tomasz Bursztyka | af6140c | 2020-05-28 20:44:16 +0200 | [diff] [blame] | 105 | const struct shared_irq_config *config = dev->config; |
Kumar Gala | a1b77fd | 2020-05-27 11:26:57 -0500 | [diff] [blame] | 106 | uint32_t i; |
Dirk Brandewie | 002c53b | 2015-09-29 08:42:22 -0700 | [diff] [blame] | 107 | |
Patrik Flykt | 8ff96b5 | 2018-11-29 11:12:22 -0800 | [diff] [blame] | 108 | for (i = 0U; i < config->client_count; i++) { |
Dirk Brandewie | 002c53b | 2015-09-29 08:42:22 -0700 | [diff] [blame] | 109 | if (clients->client[i].isr_dev == isr_dev) { |
Patrik Flykt | 24d7143 | 2019-03-26 19:57:45 -0600 | [diff] [blame] | 110 | clients->client[i].enabled = 0U; |
Dirk Brandewie | 002c53b | 2015-09-29 08:42:22 -0700 | [diff] [blame] | 111 | if (last_enabled_isr(clients, config->client_count)) { |
| 112 | irq_disable(config->irq_num); |
| 113 | } |
Andre Guedes | 024cfe7 | 2016-03-09 14:01:20 -0300 | [diff] [blame] | 114 | return 0; |
Dirk Brandewie | 002c53b | 2015-09-29 08:42:22 -0700 | [diff] [blame] | 115 | } |
| 116 | } |
Andre Guedes | 7c956d2 | 2016-03-09 14:38:02 -0300 | [diff] [blame] | 117 | return -EIO; |
Dirk Brandewie | 002c53b | 2015-09-29 08:42:22 -0700 | [diff] [blame] | 118 | } |
| 119 | |
Yong Cong Sin | f6d5c2e | 2024-09-19 16:54:40 +0800 | [diff] [blame] | 120 | static void shared_irq_isr(const struct device *dev) |
Dirk Brandewie | 002c53b | 2015-09-29 08:42:22 -0700 | [diff] [blame] | 121 | { |
Tomasz Bursztyka | 98d9b01 | 2020-05-28 21:23:02 +0200 | [diff] [blame] | 122 | struct shared_irq_runtime *clients = dev->data; |
Tomasz Bursztyka | af6140c | 2020-05-28 20:44:16 +0200 | [diff] [blame] | 123 | const struct shared_irq_config *config = dev->config; |
Kumar Gala | a1b77fd | 2020-05-27 11:26:57 -0500 | [diff] [blame] | 124 | uint32_t i; |
Dirk Brandewie | 002c53b | 2015-09-29 08:42:22 -0700 | [diff] [blame] | 125 | |
Patrik Flykt | 8ff96b5 | 2018-11-29 11:12:22 -0800 | [diff] [blame] | 126 | for (i = 0U; i < config->client_count; i++) { |
Dirk Brandewie | 002c53b | 2015-09-29 08:42:22 -0700 | [diff] [blame] | 127 | if (clients->client[i].isr_dev) { |
Navinkumar Balabakthan | a8490c3 | 2023-08-24 06:03:17 +0000 | [diff] [blame] | 128 | clients->client[i].isr_func(clients->client[i].isr_dev, config->irq_num); |
Dirk Brandewie | 002c53b | 2015-09-29 08:42:22 -0700 | [diff] [blame] | 129 | } |
| 130 | } |
| 131 | } |
| 132 | |
Pieter De Gendt | 74fc1b1 | 2024-11-28 19:33:39 +0100 | [diff] [blame] | 133 | static DEVICE_API(shared_irq, api_funcs) = { |
Dirk Brandewie | 002c53b | 2015-09-29 08:42:22 -0700 | [diff] [blame] | 134 | .isr_register = isr_register, |
| 135 | .enable = enable, |
| 136 | .disable = disable, |
| 137 | }; |
| 138 | |
| 139 | |
Yong Cong Sin | f6d5c2e | 2024-09-19 16:54:40 +0800 | [diff] [blame] | 140 | static int shared_irq_initialize(const struct device *dev) |
Dirk Brandewie | 002c53b | 2015-09-29 08:42:22 -0700 | [diff] [blame] | 141 | { |
Tomasz Bursztyka | af6140c | 2020-05-28 20:44:16 +0200 | [diff] [blame] | 142 | const struct shared_irq_config *config = dev->config; |
Yong Cong Sin | f6d5c2e | 2024-09-19 16:54:40 +0800 | [diff] [blame] | 143 | |
Andrew Boie | d9cfbd5 | 2016-01-08 00:46:14 -0800 | [diff] [blame] | 144 | config->config(); |
Dirk Brandewie | 002c53b | 2015-09-29 08:42:22 -0700 | [diff] [blame] | 145 | return 0; |
| 146 | } |
| 147 | |
Thomas Stranger | a0bea08 | 2021-03-28 17:27:36 +0200 | [diff] [blame] | 148 | /* |
| 149 | * INST_SUPPORTS_DEP_ORDS_CNT: Counts the number of "elements" in |
| 150 | * DT_SUPPORTS_DEP_ORDS(n). There is a comma after each ordinal(inc. the last) |
| 151 | * Hence FOR_EACH adds "+1" once too often which has to be subtracted in the end. |
| 152 | */ |
| 153 | #define F1(x) 1 |
| 154 | #define INST_SUPPORTS_DEP_ORDS_CNT(n) \ |
| 155 | (FOR_EACH(F1, (+), DT_INST_SUPPORTS_DEP_ORDS(n)) - 1) |
| 156 | |
Thomas Stranger | 2398203 | 2021-03-28 17:04:43 +0200 | [diff] [blame] | 157 | #define SHARED_IRQ_CONFIG_FUNC(n) \ |
| 158 | void shared_irq_config_func_##n(void) \ |
| 159 | { \ |
| 160 | IRQ_CONNECT(DT_INST_IRQN(n), \ |
| 161 | DT_INST_IRQ(n, priority), \ |
| 162 | shared_irq_isr, \ |
| 163 | DEVICE_DT_INST_GET(n), \ |
Thomas Stranger | 8f559a3 | 2021-03-28 18:13:37 +0200 | [diff] [blame] | 164 | COND_CODE_1(DT_INST_IRQ_HAS_CELL(n, sense), \ |
| 165 | (DT_INST_IRQ(n, sense)), \ |
| 166 | (0))); \ |
Dirk Brandewie | 002c53b | 2015-09-29 08:42:22 -0700 | [diff] [blame] | 167 | } |
| 168 | |
Thomas Stranger | 2398203 | 2021-03-28 17:04:43 +0200 | [diff] [blame] | 169 | #define SHARED_IRQ_INIT(n) \ |
| 170 | SHARED_IRQ_CONFIG_FUNC(n) \ |
Thomas Stranger | dedd444 | 2021-03-28 18:07:56 +0200 | [diff] [blame] | 171 | struct shared_irq_client clients_##n[INST_SUPPORTS_DEP_ORDS_CNT(n)]; \ |
| 172 | struct shared_irq_runtime shared_irq_data_##n = { \ |
| 173 | .client = clients_##n \ |
| 174 | }; \ |
Thomas Stranger | 2398203 | 2021-03-28 17:04:43 +0200 | [diff] [blame] | 175 | \ |
| 176 | const struct shared_irq_config shared_irq_config_##n = { \ |
| 177 | .irq_num = DT_INST_IRQN(n), \ |
Thomas Stranger | a0bea08 | 2021-03-28 17:27:36 +0200 | [diff] [blame] | 178 | .client_count = INST_SUPPORTS_DEP_ORDS_CNT(n), \ |
Thomas Stranger | 2398203 | 2021-03-28 17:04:43 +0200 | [diff] [blame] | 179 | .config = shared_irq_config_func_##n \ |
| 180 | }; \ |
| 181 | DEVICE_DT_INST_DEFINE(n, shared_irq_initialize, \ |
| 182 | NULL, \ |
| 183 | &shared_irq_data_##n, \ |
| 184 | &shared_irq_config_##n, POST_KERNEL, \ |
| 185 | CONFIG_SHARED_IRQ_INIT_PRIORITY, \ |
| 186 | &api_funcs); |
Dirk Brandewie | 002c53b | 2015-09-29 08:42:22 -0700 | [diff] [blame] | 187 | |
Thomas Stranger | 2398203 | 2021-03-28 17:04:43 +0200 | [diff] [blame] | 188 | DT_INST_FOREACH_STATUS_OKAY(SHARED_IRQ_INIT) |