irq-mbigen.c (76e1f77f9c26ec96ce58f46cc74ad07c731bd7ba) irq-mbigen.c (f907c515ffb06e6fd5e74397badd674f3c233418)
1/*
2 * Copyright (C) 2015 Hisilicon Limited, All Rights Reserved.
3 * Author: Jun Ma <majun258@huawei.com>
4 * Author: Yun Wu <wuyun.wu@huawei.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
1/*
2 * Copyright (C) 2015 Hisilicon Limited, All Rights Reserved.
3 * Author: Jun Ma <majun258@huawei.com>
4 * Author: Yun Wu <wuyun.wu@huawei.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <linux/acpi.h>
19#include <linux/interrupt.h>
20#include <linux/irqchip.h>
21#include <linux/module.h>
22#include <linux/msi.h>
23#include <linux/of_address.h>
24#include <linux/of_irq.h>
25#include <linux/of_platform.h>
26#include <linux/platform_device.h>

--- 148 unchanged lines hidden (view full) ---

175 writel_relaxed(val, base);
176}
177
178static int mbigen_domain_translate(struct irq_domain *d,
179 struct irq_fwspec *fwspec,
180 unsigned long *hwirq,
181 unsigned int *type)
182{
20#include <linux/interrupt.h>
21#include <linux/irqchip.h>
22#include <linux/module.h>
23#include <linux/msi.h>
24#include <linux/of_address.h>
25#include <linux/of_irq.h>
26#include <linux/of_platform.h>
27#include <linux/platform_device.h>

--- 148 unchanged lines hidden (view full) ---

176 writel_relaxed(val, base);
177}
178
179static int mbigen_domain_translate(struct irq_domain *d,
180 struct irq_fwspec *fwspec,
181 unsigned long *hwirq,
182 unsigned int *type)
183{
183 if (is_of_node(fwspec->fwnode)) {
184 if (is_of_node(fwspec->fwnode) || is_acpi_device_node(fwspec->fwnode)) {
184 if (fwspec->param_count != 2)
185 return -EINVAL;
186
187 if ((fwspec->param[0] > MAXIMUM_IRQ_PIN_NUM) ||
188 (fwspec->param[0] < RESERVED_IRQ_PER_MBIGEN_CHIP))
189 return -EINVAL;
190 else
191 *hwirq = fwspec->param[0];

--- 74 unchanged lines hidden (view full) ---

266 mgn_chip);
267 if (!domain)
268 return -ENOMEM;
269 }
270
271 return 0;
272}
273
185 if (fwspec->param_count != 2)
186 return -EINVAL;
187
188 if ((fwspec->param[0] > MAXIMUM_IRQ_PIN_NUM) ||
189 (fwspec->param[0] < RESERVED_IRQ_PER_MBIGEN_CHIP))
190 return -EINVAL;
191 else
192 *hwirq = fwspec->param[0];

--- 74 unchanged lines hidden (view full) ---

267 mgn_chip);
268 if (!domain)
269 return -ENOMEM;
270 }
271
272 return 0;
273}
274
275#ifdef CONFIG_ACPI
276static int mbigen_acpi_create_domain(struct platform_device *pdev,
277 struct mbigen_device *mgn_chip)
278{
279 struct irq_domain *domain;
280 u32 num_pins = 0;
281 int ret;
282
283 /*
284 * "num-pins" is the total number of interrupt pins implemented in
285 * this mbigen instance, and mbigen is an interrupt controller
286 * connected to ITS converting wired interrupts into MSI, so we
287 * use "num-pins" to alloc MSI vectors which are needed by client
288 * devices connected to it.
289 *
290 * Here is the DSDT device node used for mbigen in firmware:
291 * Device(MBI0) {
292 * Name(_HID, "HISI0152")
293 * Name(_UID, Zero)
294 * Name(_CRS, ResourceTemplate() {
295 * Memory32Fixed(ReadWrite, 0xa0080000, 0x10000)
296 * })
297 *
298 * Name(_DSD, Package () {
299 * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
300 * Package () {
301 * Package () {"num-pins", 378}
302 * }
303 * })
304 * }
305 */
306 ret = device_property_read_u32(&pdev->dev, "num-pins", &num_pins);
307 if (ret || num_pins == 0)
308 return -EINVAL;
309
310 domain = platform_msi_create_device_domain(&pdev->dev, num_pins,
311 mbigen_write_msg,
312 &mbigen_domain_ops,
313 mgn_chip);
314 if (!domain)
315 return -ENOMEM;
316
317 return 0;
318}
319#else
320static inline int mbigen_acpi_create_domain(struct platform_device *pdev,
321 struct mbigen_device *mgn_chip)
322{
323 return -ENODEV;
324}
325#endif
326
274static int mbigen_device_probe(struct platform_device *pdev)
275{
276 struct mbigen_device *mgn_chip;
277 struct resource *res;
278 int err;
279
280 mgn_chip = devm_kzalloc(&pdev->dev, sizeof(*mgn_chip), GFP_KERNEL);
281 if (!mgn_chip)
282 return -ENOMEM;
283
284 mgn_chip->pdev = pdev;
285
286 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
287 mgn_chip->base = devm_ioremap(&pdev->dev, res->start,
288 resource_size(res));
289 if (IS_ERR(mgn_chip->base))
290 return PTR_ERR(mgn_chip->base);
291
327static int mbigen_device_probe(struct platform_device *pdev)
328{
329 struct mbigen_device *mgn_chip;
330 struct resource *res;
331 int err;
332
333 mgn_chip = devm_kzalloc(&pdev->dev, sizeof(*mgn_chip), GFP_KERNEL);
334 if (!mgn_chip)
335 return -ENOMEM;
336
337 mgn_chip->pdev = pdev;
338
339 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
340 mgn_chip->base = devm_ioremap(&pdev->dev, res->start,
341 resource_size(res));
342 if (IS_ERR(mgn_chip->base))
343 return PTR_ERR(mgn_chip->base);
344
292 err = mbigen_of_create_domain(pdev, mgn_chip);
293 if (err)
345 if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node)
346 err = mbigen_of_create_domain(pdev, mgn_chip);
347 else if (ACPI_COMPANION(&pdev->dev))
348 err = mbigen_acpi_create_domain(pdev, mgn_chip);
349 else
350 err = -EINVAL;
351
352 if (err) {
353 dev_err(&pdev->dev, "Failed to create mbi-gen@%p irqdomain",
354 mgn_chip->base);
294 return err;
355 return err;
356 }
295
296 platform_set_drvdata(pdev, mgn_chip);
297 return 0;
298}
299
300static const struct of_device_id mbigen_of_match[] = {
301 { .compatible = "hisilicon,mbigen-v2" },
302 { /* END */ }
303};
304MODULE_DEVICE_TABLE(of, mbigen_of_match);
305
357
358 platform_set_drvdata(pdev, mgn_chip);
359 return 0;
360}
361
362static const struct of_device_id mbigen_of_match[] = {
363 { .compatible = "hisilicon,mbigen-v2" },
364 { /* END */ }
365};
366MODULE_DEVICE_TABLE(of, mbigen_of_match);
367
368static const struct acpi_device_id mbigen_acpi_match[] = {
369 { "HISI0152", 0 },
370 {}
371};
372MODULE_DEVICE_TABLE(acpi, mbigen_acpi_match);
373
306static struct platform_driver mbigen_platform_driver = {
307 .driver = {
308 .name = "Hisilicon MBIGEN-V2",
309 .of_match_table = mbigen_of_match,
374static struct platform_driver mbigen_platform_driver = {
375 .driver = {
376 .name = "Hisilicon MBIGEN-V2",
377 .of_match_table = mbigen_of_match,
378 .acpi_match_table = ACPI_PTR(mbigen_acpi_match),
310 },
311 .probe = mbigen_device_probe,
312};
313
314module_platform_driver(mbigen_platform_driver);
315
316MODULE_AUTHOR("Jun Ma <majun258@huawei.com>");
317MODULE_AUTHOR("Yun Wu <wuyun.wu@huawei.com>");
318MODULE_LICENSE("GPL");
319MODULE_DESCRIPTION("Hisilicon MBI Generator driver");
379 },
380 .probe = mbigen_device_probe,
381};
382
383module_platform_driver(mbigen_platform_driver);
384
385MODULE_AUTHOR("Jun Ma <majun258@huawei.com>");
386MODULE_AUTHOR("Yun Wu <wuyun.wu@huawei.com>");
387MODULE_LICENSE("GPL");
388MODULE_DESCRIPTION("Hisilicon MBI Generator driver");