mirror of
https://github.com/torvalds/linux.git
synced 2026-05-12 16:18:45 +02:00
RISC-V soc drivers for v7.1
Microchip: Add coverage for the pic64gx in the system controller and syscons. Add a interrupt mux driver (akin to the one that Renesas recently added) that fixes a problem where the platform never properly modelled gpio interrupts. There's a gpio driver change here that Bartosz has acked that adds the interrupt support to the GPIO driver itself. Signed-off-by: Conor Dooley <conor.dooley@microchip.com> -----BEGIN PGP SIGNATURE----- iHUEABYKAB0WIQRh246EGq/8RLhDjO14tDGHoIJi0gUCadOMGgAKCRB4tDGHoIJi 0gXaAP9j6X7ZAL+EOJqiUjQUVslWZUv+hZrKOCv1InnSHDkC5gEAovr3nk6yHjt0 a+4XnUj8AGPbT4bcFEdzeArmH//QtgA= =+V3B -----END PGP SIGNATURE----- Merge tag 'riscv-soc-drivers-for-v7.1' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/conor/linux into soc/drivers RISC-V soc drivers for v7.1 Microchip: Add coverage for the pic64gx in the system controller and syscons. Add a interrupt mux driver (akin to the one that Renesas recently added) that fixes a problem where the platform never properly modelled gpio interrupts. There's a gpio driver change here that Bartosz has acked that adds the interrupt support to the GPIO driver itself. Signed-off-by: Conor Dooley <conor.dooley@microchip.com> * tag 'riscv-soc-drivers-for-v7.1' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/conor/linux: soc: microchip: add mpfs gpio interrupt mux driver dt-bindings: soc: microchip: document PolarFire SoC's gpio interrupt mux gpio: mpfs: Add interrupt support soc: microchip: mpfs-sys-controller: add support for pic64gx dt-bindings: soc: microchip: mpfs-sys-controller: Add pic64gx compatibility dt-bindings: soc: microchip: add compatible for the mss-top-sysreg on pic64gx Signed-off-by: Krzysztof Kozlowski <krzk@kernel.org>
This commit is contained in:
commit
ecaf3a92fb
|
|
@ -0,0 +1,103 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/soc/microchip/microchip,mpfs-irqmux.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Microchip Polarfire SoC GPIO Interrupt Mux
|
||||
|
||||
maintainers:
|
||||
- Conor Dooley <conor.dooley@microchip.com>
|
||||
|
||||
description: |
|
||||
There are 3 GPIO controllers on this SoC, of which:
|
||||
- GPIO controller 0 has 14 GPIOs
|
||||
- GPIO controller 1 has 24 GPIOs
|
||||
- GPIO controller 2 has 32 GPIOs
|
||||
|
||||
All GPIOs are capable of generating interrupts, for a total of 70.
|
||||
There are only 41 IRQs available however, so a configurable mux is used to
|
||||
ensure all GPIOs can be used for interrupt generation.
|
||||
38 of the 41 interrupts are in what the documentation calls "direct mode",
|
||||
as they provide an exclusive connection from a GPIO to the PLIC.
|
||||
Lines 18 to 23 on GPIO controller 1 are always in "direct mode".
|
||||
The 3 remaining interrupts are used to mux the interrupts which do not have
|
||||
a exclusive connection, one for each GPIO controller.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: microchip,mpfs-irqmux
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
"#address-cells":
|
||||
const: 0
|
||||
|
||||
"#interrupt-cells":
|
||||
const: 1
|
||||
|
||||
interrupt-map-mask:
|
||||
items:
|
||||
- const: 0x7f
|
||||
|
||||
interrupt-map:
|
||||
description: |
|
||||
Specifies the mapping from GPIO interrupt lines to plic interrupts.
|
||||
|
||||
The child interrupt number set in arrays items is computed using the
|
||||
following formula:
|
||||
gpio_bank * 32 + gpio_number
|
||||
with:
|
||||
- gpio_bank: The GPIO bank number
|
||||
- 0 for GPIO0,
|
||||
- 1 for GPIO1,
|
||||
- 2 for GPIO2
|
||||
- gpio_number: Number of the gpio in the bank (0..31)
|
||||
maxItems: 70
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- "#address-cells"
|
||||
- "#interrupt-cells"
|
||||
- interrupt-map-mask
|
||||
- interrupt-map
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
interrupt-controller@54 {
|
||||
compatible = "microchip,mpfs-irqmux";
|
||||
reg = <0x54 0x4>;
|
||||
#address-cells = <0>;
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-map-mask = <0x7f>;
|
||||
interrupt-map = <0 &plic 13>, <1 &plic 14>, <2 &plic 15>,
|
||||
<3 &plic 16>, <4 &plic 17>, <5 &plic 18>,
|
||||
<6 &plic 19>, <7 &plic 20>, <8 &plic 21>,
|
||||
<9 &plic 22>, <10 &plic 23>, <11 &plic 24>,
|
||||
<12 &plic 25>, <13 &plic 26>,
|
||||
|
||||
<32 &plic 27>, <33 &plic 28>, <34 &plic 29>,
|
||||
<35 &plic 30>, <36 &plic 31>, <37 &plic 32>,
|
||||
<38 &plic 33>, <39 &plic 34>, <40 &plic 35>,
|
||||
<41 &plic 36>, <42 &plic 37>, <43 &plic 38>,
|
||||
<44 &plic 39>, <45 &plic 40>, <46 &plic 41>,
|
||||
<47 &plic 42>, <48 &plic 43>, <49 &plic 44>,
|
||||
<50 &plic 45>, <51 &plic 46>, <52 &plic 47>,
|
||||
<53 &plic 48>, <54 &plic 49>, <55 &plic 50>,
|
||||
|
||||
<64 &plic 53>, <65 &plic 53>, <66 &plic 53>,
|
||||
<67 &plic 53>, <68 &plic 53>, <69 &plic 53>,
|
||||
<70 &plic 53>, <71 &plic 53>, <72 &plic 53>,
|
||||
<73 &plic 53>, <74 &plic 53>, <75 &plic 53>,
|
||||
<76 &plic 53>, <77 &plic 53>, <78 &plic 53>,
|
||||
<79 &plic 53>, <80 &plic 53>, <81 &plic 53>,
|
||||
<82 &plic 53>, <83 &plic 53>, <84 &plic 53>,
|
||||
<85 &plic 53>, <86 &plic 53>, <87 &plic 53>,
|
||||
<88 &plic 53>, <89 &plic 53>, <90 &plic 53>,
|
||||
<91 &plic 53>, <92 &plic 53>, <93 &plic 53>,
|
||||
<94 &plic 53>, <95 &plic 53>;
|
||||
};
|
||||
|
|
@ -15,10 +15,16 @@ description:
|
|||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- const: microchip,mpfs-mss-top-sysreg
|
||||
- const: syscon
|
||||
- const: simple-mfd
|
||||
oneOf:
|
||||
- items:
|
||||
- const: microchip,mpfs-mss-top-sysreg
|
||||
- const: syscon
|
||||
- const: simple-mfd
|
||||
- items:
|
||||
- const: microchip,pic64gx-mss-top-sysreg
|
||||
- const: microchip,mpfs-mss-top-sysreg
|
||||
- const: syscon
|
||||
- const: simple-mfd
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
|
@ -38,6 +44,10 @@ properties:
|
|||
of PolarFire clock/reset IDs.
|
||||
const: 1
|
||||
|
||||
interrupt-controller@54:
|
||||
type: object
|
||||
$ref: /schemas/soc/microchip/microchip,mpfs-irqmux.yaml
|
||||
|
||||
pinctrl@200:
|
||||
type: object
|
||||
$ref: /schemas/pinctrl/microchip,mpfs-pinctrl-iomux0.yaml
|
||||
|
|
|
|||
|
|
@ -24,7 +24,9 @@ properties:
|
|||
maxItems: 1
|
||||
|
||||
compatible:
|
||||
const: microchip,mpfs-sys-controller
|
||||
enum:
|
||||
- microchip,mpfs-sys-controller
|
||||
- microchip,pic64gx-sys-controller
|
||||
|
||||
microchip,bitstream-flash:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
|
|
|
|||
|
|
@ -22733,7 +22733,7 @@ F: Documentation/devicetree/bindings/pinctrl/microchip,mpfs-pinctrl-mssio.yaml
|
|||
F: Documentation/devicetree/bindings/pinctrl/microchip,pic64gx-pinctrl-gpio2.yaml
|
||||
F: Documentation/devicetree/bindings/pwm/microchip,corepwm.yaml
|
||||
F: Documentation/devicetree/bindings/riscv/microchip.yaml
|
||||
F: Documentation/devicetree/bindings/soc/microchip/microchip,mpfs-sys-controller.yaml
|
||||
F: Documentation/devicetree/bindings/soc/microchip/microchip,mpfs*.yaml
|
||||
F: Documentation/devicetree/bindings/spi/microchip,mpfs-spi.yaml
|
||||
F: Documentation/devicetree/bindings/usb/microchip,mpfs-musb.yaml
|
||||
F: arch/riscv/boot/dts/microchip/
|
||||
|
|
|
|||
|
|
@ -572,6 +572,7 @@ config GPIO_PL061
|
|||
config GPIO_POLARFIRE_SOC
|
||||
bool "Microchip FPGA GPIO support"
|
||||
select REGMAP_MMIO
|
||||
select GPIOLIB_IRQCHIP
|
||||
help
|
||||
Say yes here to support the GPIO controllers on Microchip FPGAs.
|
||||
|
||||
|
|
|
|||
|
|
@ -9,8 +9,9 @@
|
|||
#include <linux/device.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/regmap.h>
|
||||
|
|
@ -18,7 +19,7 @@
|
|||
|
||||
#define MPFS_GPIO_CTRL(i) (0x4 * (i))
|
||||
#define MPFS_MAX_NUM_GPIO 32
|
||||
#define MPFS_GPIO_EN_INT 3
|
||||
#define MPFS_GPIO_EN_INT BIT(3)
|
||||
#define MPFS_GPIO_EN_OUT_BUF BIT(2)
|
||||
#define MPFS_GPIO_EN_IN BIT(1)
|
||||
#define MPFS_GPIO_EN_OUT BIT(0)
|
||||
|
|
@ -52,6 +53,7 @@ static const struct regmap_config mpfs_gpio_regmap_config = {
|
|||
.reg_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.val_bits = 32,
|
||||
.use_raw_spinlock = true,
|
||||
};
|
||||
|
||||
static int mpfs_gpio_direction_input(struct gpio_chip *gc, unsigned int gpio_index)
|
||||
|
|
@ -114,13 +116,98 @@ static int mpfs_gpio_set(struct gpio_chip *gc, unsigned int gpio_index, int valu
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int mpfs_gpio_irq_set_type(struct irq_data *data, unsigned int type)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
|
||||
struct mpfs_gpio_chip *mpfs_gpio = gpiochip_get_data(gc);
|
||||
int gpio_index = irqd_to_hwirq(data) % 32;
|
||||
u32 interrupt_type;
|
||||
|
||||
switch (type) {
|
||||
case IRQ_TYPE_EDGE_BOTH:
|
||||
interrupt_type = MPFS_GPIO_TYPE_INT_EDGE_BOTH;
|
||||
break;
|
||||
case IRQ_TYPE_EDGE_FALLING:
|
||||
interrupt_type = MPFS_GPIO_TYPE_INT_EDGE_NEG;
|
||||
break;
|
||||
case IRQ_TYPE_EDGE_RISING:
|
||||
interrupt_type = MPFS_GPIO_TYPE_INT_EDGE_POS;
|
||||
break;
|
||||
case IRQ_TYPE_LEVEL_HIGH:
|
||||
interrupt_type = MPFS_GPIO_TYPE_INT_LEVEL_HIGH;
|
||||
break;
|
||||
case IRQ_TYPE_LEVEL_LOW:
|
||||
interrupt_type = MPFS_GPIO_TYPE_INT_LEVEL_LOW;
|
||||
break;
|
||||
}
|
||||
|
||||
regmap_update_bits(mpfs_gpio->regs, MPFS_GPIO_CTRL(gpio_index),
|
||||
MPFS_GPIO_TYPE_INT_MASK, interrupt_type);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mpfs_gpio_irq_unmask(struct irq_data *data)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
|
||||
struct mpfs_gpio_chip *mpfs_gpio = gpiochip_get_data(gc);
|
||||
int gpio_index = irqd_to_hwirq(data) % 32;
|
||||
|
||||
gpiochip_enable_irq(gc, gpio_index);
|
||||
mpfs_gpio_direction_input(gc, gpio_index);
|
||||
regmap_update_bits(mpfs_gpio->regs, MPFS_GPIO_CTRL(gpio_index),
|
||||
MPFS_GPIO_EN_INT, MPFS_GPIO_EN_INT);
|
||||
}
|
||||
|
||||
static void mpfs_gpio_irq_mask(struct irq_data *data)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
|
||||
struct mpfs_gpio_chip *mpfs_gpio = gpiochip_get_data(gc);
|
||||
int gpio_index = irqd_to_hwirq(data) % 32;
|
||||
|
||||
regmap_update_bits(mpfs_gpio->regs, MPFS_GPIO_CTRL(gpio_index),
|
||||
MPFS_GPIO_EN_INT, 0);
|
||||
gpiochip_disable_irq(gc, gpio_index);
|
||||
}
|
||||
|
||||
static const struct irq_chip mpfs_gpio_irqchip = {
|
||||
.name = "MPFS GPIO",
|
||||
.irq_set_type = mpfs_gpio_irq_set_type,
|
||||
.irq_mask = mpfs_gpio_irq_mask,
|
||||
.irq_unmask = mpfs_gpio_irq_unmask,
|
||||
.flags = IRQCHIP_IMMUTABLE | IRQCHIP_MASK_ON_SUSPEND,
|
||||
GPIOCHIP_IRQ_RESOURCE_HELPERS,
|
||||
};
|
||||
|
||||
static void mpfs_gpio_irq_handler(struct irq_desc *desc)
|
||||
{
|
||||
struct irq_chip *irqchip = irq_desc_get_chip(desc);
|
||||
struct mpfs_gpio_chip *mpfs_gpio = irq_desc_get_handler_data(desc);
|
||||
unsigned long status;
|
||||
u32 val;
|
||||
int i;
|
||||
|
||||
chained_irq_enter(irqchip, desc);
|
||||
|
||||
regmap_read(mpfs_gpio->regs, MPFS_IRQ_REG, &val);
|
||||
status = val;
|
||||
for_each_set_bit(i, &status, MPFS_MAX_NUM_GPIO) {
|
||||
regmap_write(mpfs_gpio->regs, MPFS_IRQ_REG, BIT(i));
|
||||
generic_handle_domain_irq(mpfs_gpio->gc.irq.domain, i);
|
||||
}
|
||||
|
||||
chained_irq_exit(irqchip, desc);
|
||||
}
|
||||
|
||||
static int mpfs_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *node = dev->of_node;
|
||||
struct mpfs_gpio_chip *mpfs_gpio;
|
||||
struct gpio_irq_chip *girq;
|
||||
struct clk *clk;
|
||||
void __iomem *base;
|
||||
int ngpios;
|
||||
int ngpios, nirqs, ret;
|
||||
|
||||
mpfs_gpio = devm_kzalloc(dev, sizeof(*mpfs_gpio), GFP_KERNEL);
|
||||
if (!mpfs_gpio)
|
||||
|
|
@ -157,6 +244,35 @@ static int mpfs_gpio_probe(struct platform_device *pdev)
|
|||
mpfs_gpio->gc.parent = dev;
|
||||
mpfs_gpio->gc.owner = THIS_MODULE;
|
||||
|
||||
nirqs = of_irq_count(node);
|
||||
if (nirqs > MPFS_MAX_NUM_GPIO)
|
||||
return -ENXIO;
|
||||
|
||||
if (nirqs) {
|
||||
girq = &mpfs_gpio->gc.irq;
|
||||
|
||||
gpio_irq_chip_set_chip(girq, &mpfs_gpio_irqchip);
|
||||
|
||||
girq->num_parents = nirqs;
|
||||
girq->parents = devm_kcalloc(&pdev->dev, girq->num_parents,
|
||||
sizeof(*girq->parents), GFP_KERNEL);
|
||||
if (!girq->parents)
|
||||
return -ENOMEM;
|
||||
|
||||
for (int i = 0; i < nirqs; i++) {
|
||||
ret = platform_get_irq(pdev, i);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
girq->parents[i] = ret;
|
||||
girq->parent_handler_data = mpfs_gpio;
|
||||
girq->parent_handler = mpfs_gpio_irq_handler;
|
||||
}
|
||||
|
||||
girq->handler = handle_level_irq;
|
||||
girq->default_type = IRQ_TYPE_NONE;
|
||||
}
|
||||
|
||||
return devm_gpiochip_add_data(dev, &mpfs_gpio->gc, mpfs_gpio);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,14 @@
|
|||
config POLARFIRE_SOC_IRQ_MUX
|
||||
bool "Microchip PolarFire SoC's GPIO IRQ Mux"
|
||||
depends on ARCH_MICROCHIP
|
||||
select REGMAP
|
||||
select REGMAP_MMIO
|
||||
default y
|
||||
help
|
||||
Support for the interrupt mux on Polarfire SoC. It sits between
|
||||
the GPIO controllers and the PLIC, as only 41 interrupts are shared
|
||||
between 3 GPIO controllers with a total of 70 interrupts.
|
||||
|
||||
config POLARFIRE_SOC_SYS_CTRL
|
||||
tristate "Microchip PolarFire SoC (MPFS) system controller support"
|
||||
depends on POLARFIRE_SOC_MAILBOX
|
||||
|
|
|
|||
|
|
@ -1,2 +1,3 @@
|
|||
obj-$(CONFIG_POLARFIRE_SOC_IRQ_MUX) += mpfs-irqmux.o
|
||||
obj-$(CONFIG_POLARFIRE_SOC_SYS_CTRL) += mpfs-sys-controller.o
|
||||
obj-$(CONFIG_POLARFIRE_SOC_SYSCONS) += mpfs-control-scb.o mpfs-mss-top-sysreg.o
|
||||
|
|
|
|||
181
drivers/soc/microchip/mpfs-irqmux.c
Normal file
181
drivers/soc/microchip/mpfs-irqmux.c
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Largely copied from rzn1_irqmux.c
|
||||
*/
|
||||
|
||||
#include <linux/bitmap.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#define MPFS_IRQMUX_CR 0x54
|
||||
#define MPFS_IRQMUX_NUM_CHILDREN 96
|
||||
#define MPFS_IRQMUX_NUM_DIRECT 38
|
||||
#define MPFS_IRQMUX_DIRECT_START 13
|
||||
#define MPFS_IRQMUX_DIRECT_END 50
|
||||
#define MPFS_IRQMUX_NONDIRECT_END 53
|
||||
|
||||
static int mpfs_irqmux_is_direct_mode(struct device *dev,
|
||||
const struct of_phandle_args *parent_args)
|
||||
{
|
||||
if (parent_args->args_count != 1) {
|
||||
dev_err(dev, "Invalid interrupt-map item\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (parent_args->args[0] < MPFS_IRQMUX_DIRECT_START ||
|
||||
parent_args->args[0] > MPFS_IRQMUX_NONDIRECT_END) {
|
||||
dev_err(dev, "Invalid interrupt %u\n", parent_args->args[0]);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (parent_args->args[0] > MPFS_IRQMUX_DIRECT_END)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int mpfs_irqmux_probe(struct platform_device *pdev)
|
||||
{
|
||||
DECLARE_BITMAP(child_done, MPFS_IRQMUX_NUM_CHILDREN) = {};
|
||||
DECLARE_BITMAP(parent_done, MPFS_IRQMUX_NUM_DIRECT) = {};
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct of_imap_parser imap_parser;
|
||||
struct of_imap_item imap_item;
|
||||
struct regmap *regmap;
|
||||
int ret, direct_mode, line, controller, gpio, parent_line;
|
||||
u32 tmp, val = 0, old;
|
||||
|
||||
regmap = device_node_to_regmap(pdev->dev.parent->of_node);
|
||||
if (IS_ERR(regmap))
|
||||
return dev_err_probe(dev, PTR_ERR(regmap), "Failed to find syscon regmap\n");
|
||||
|
||||
/* We support only #interrupt-cells = <1> and #address-cells = <0> */
|
||||
ret = of_property_read_u32(np, "#interrupt-cells", &tmp);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (tmp != 1)
|
||||
return -EINVAL;
|
||||
|
||||
ret = of_property_read_u32(np, "#address-cells", &tmp);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (tmp != 0)
|
||||
return -EINVAL;
|
||||
|
||||
ret = of_imap_parser_init(&imap_parser, np, &imap_item);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for_each_of_imap_item(&imap_parser, &imap_item) {
|
||||
|
||||
direct_mode = mpfs_irqmux_is_direct_mode(dev, &imap_item.parent_args);
|
||||
if (direct_mode < 0) {
|
||||
of_node_put(imap_item.parent_args.np);
|
||||
return direct_mode;
|
||||
}
|
||||
|
||||
line = imap_item.child_imap[0];
|
||||
gpio = line % 32;
|
||||
controller = line / 32;
|
||||
|
||||
if (controller > 2) {
|
||||
of_node_put(imap_item.parent_args.np);
|
||||
dev_err(dev, "child interrupt number too large: %d\n", line);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (test_and_set_bit(line, child_done)) {
|
||||
of_node_put(imap_item.parent_args.np);
|
||||
dev_err(dev, "mux child line %d already defined in interrupt-map\n",
|
||||
line);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
parent_line = imap_item.parent_args.args[0] - MPFS_IRQMUX_DIRECT_START;
|
||||
if (direct_mode && test_and_set_bit(parent_line, parent_done)) {
|
||||
of_node_put(imap_item.parent_args.np);
|
||||
dev_err(dev, "mux parent line %d already defined in interrupt-map\n",
|
||||
line);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* There are 41 interrupts assigned to GPIOs, of which 38 are "direct". Since the
|
||||
* mux has 32 bits only, 6 of these exclusive/"direct" interrupts remain. These
|
||||
* are used by GPIO controller 1's lines 18 to 23. Nothing needs to be done
|
||||
* for these interrupts.
|
||||
*/
|
||||
if (controller == 1 && gpio >= 18)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* The mux has a single register, where bits 0 to 13 mux between GPIO controller
|
||||
* 1's 14 GPIOs and GPIO controller 2's first 14 GPIOs. The remaining bits mux
|
||||
* between the first 18 GPIOs of controller 1 and the last 18 GPIOS of
|
||||
* controller 2. If a bit in the mux's control register is set, the
|
||||
* corresponding interrupt line for GPIO controller 0 or 1 will be put in
|
||||
* "non-direct" mode. If cleared, the "fabric" controller's will.
|
||||
*
|
||||
* Register layout:
|
||||
* GPIO 1 interrupt line 17 | mux bit 31 | GPIO 2 interrupt line 31
|
||||
* ... | ... | ...
|
||||
* ... | ... | ...
|
||||
* GPIO 1 interrupt line 0 | mux bit 14 | GPIO 2 interrupt line 14
|
||||
* GPIO 0 interrupt line 13 | mux bit 13 | GPIO 2 interrupt line 13
|
||||
* ... | ... | ...
|
||||
* ... | ... | ...
|
||||
* GPIO 0 interrupt line 0 | mux bit 0 | GPIO 2 interrupt line 0
|
||||
*
|
||||
* As the binding mandates 70 items, one for each GPIO line, there's no need to
|
||||
* handle anything for GPIO controller 2, since the bit will be set for the
|
||||
* corresponding line in GPIO controller 0 or 1.
|
||||
*/
|
||||
if (controller == 2)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* If in direct mode, the bit is cleared, nothing needs to be done as val is zero
|
||||
* initialised and that's the direct mode setting for GPIO controller 0 and 1.
|
||||
*/
|
||||
if (direct_mode)
|
||||
continue;
|
||||
|
||||
if (controller == 0)
|
||||
val |= 1U << gpio;
|
||||
else
|
||||
val |= 1U << (gpio + 14);
|
||||
}
|
||||
|
||||
regmap_read(regmap, MPFS_IRQMUX_CR, &old);
|
||||
regmap_write(regmap, MPFS_IRQMUX_CR, val);
|
||||
|
||||
if (val != old)
|
||||
dev_info(dev, "firmware mux setting of 0x%x overwritten to 0x%x\n", old, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id mpfs_irqmux_of_match[] = {
|
||||
{ .compatible = "microchip,mpfs-irqmux", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mpfs_irqmux_of_match);
|
||||
|
||||
static struct platform_driver mpfs_irqmux_driver = {
|
||||
.probe = mpfs_irqmux_probe,
|
||||
.driver = {
|
||||
.name = "mpfs_irqmux",
|
||||
.of_match_table = mpfs_irqmux_of_match,
|
||||
},
|
||||
};
|
||||
module_platform_driver(mpfs_irqmux_driver);
|
||||
|
||||
MODULE_AUTHOR("Conor Dooley <conor.dooley@microchip.com>");
|
||||
MODULE_DESCRIPTION("Polarfire SoC interrupt mux driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
@ -36,6 +36,11 @@ struct mpfs_sys_controller {
|
|||
struct kref consumers;
|
||||
};
|
||||
|
||||
struct mpfs_syscon_config {
|
||||
unsigned int nb_subdevs;
|
||||
struct platform_device *subdevs;
|
||||
};
|
||||
|
||||
int mpfs_blocking_transaction(struct mpfs_sys_controller *sys_controller, struct mpfs_mss_msg *msg)
|
||||
{
|
||||
unsigned long timeout = msecs_to_jiffies(MPFS_SYS_CTRL_TIMEOUT_MS);
|
||||
|
|
@ -110,25 +115,11 @@ struct mtd_info *mpfs_sys_controller_get_flash(struct mpfs_sys_controller *mpfs_
|
|||
}
|
||||
EXPORT_SYMBOL(mpfs_sys_controller_get_flash);
|
||||
|
||||
static struct platform_device subdevs[] = {
|
||||
{
|
||||
.name = "mpfs-rng",
|
||||
.id = -1,
|
||||
},
|
||||
{
|
||||
.name = "mpfs-generic-service",
|
||||
.id = -1,
|
||||
},
|
||||
{
|
||||
.name = "mpfs-auto-update",
|
||||
.id = -1,
|
||||
},
|
||||
};
|
||||
|
||||
static int mpfs_sys_controller_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct mpfs_sys_controller *sys_controller;
|
||||
struct mpfs_syscon_config *of_data;
|
||||
struct device_node *np;
|
||||
int i, ret;
|
||||
|
||||
|
|
@ -164,11 +155,17 @@ static int mpfs_sys_controller_probe(struct platform_device *pdev)
|
|||
|
||||
platform_set_drvdata(pdev, sys_controller);
|
||||
|
||||
of_data = (struct mpfs_syscon_config *) device_get_match_data(dev);
|
||||
if (!of_data) {
|
||||
dev_err(dev, "Error getting match data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(subdevs); i++) {
|
||||
subdevs[i].dev.parent = dev;
|
||||
if (platform_device_register(&subdevs[i]))
|
||||
dev_warn(dev, "Error registering sub device %s\n", subdevs[i].name);
|
||||
for (i = 0; i < of_data->nb_subdevs; i++) {
|
||||
of_data->subdevs[i].dev.parent = dev;
|
||||
if (platform_device_register(&of_data->subdevs[i]))
|
||||
dev_warn(dev, "Error registering sub device %s\n",
|
||||
of_data->subdevs[i].name);
|
||||
}
|
||||
|
||||
dev_info(&pdev->dev, "Registered MPFS system controller\n");
|
||||
|
|
@ -183,8 +180,45 @@ static void mpfs_sys_controller_remove(struct platform_device *pdev)
|
|||
mpfs_sys_controller_put(sys_controller);
|
||||
}
|
||||
|
||||
static struct platform_device mpfs_subdevs[] = {
|
||||
{
|
||||
.name = "mpfs-rng",
|
||||
.id = -1,
|
||||
},
|
||||
{
|
||||
.name = "mpfs-generic-service",
|
||||
.id = -1,
|
||||
},
|
||||
{
|
||||
.name = "mpfs-auto-update",
|
||||
.id = -1,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device pic64gx_subdevs[] = {
|
||||
{
|
||||
.name = "mpfs-rng",
|
||||
.id = -1,
|
||||
},
|
||||
{
|
||||
.name = "mpfs-generic-service",
|
||||
.id = -1,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct mpfs_syscon_config mpfs_config = {
|
||||
.nb_subdevs = ARRAY_SIZE(mpfs_subdevs),
|
||||
.subdevs = mpfs_subdevs,
|
||||
};
|
||||
|
||||
static const struct mpfs_syscon_config pic64gx_config = {
|
||||
.nb_subdevs = ARRAY_SIZE(pic64gx_subdevs),
|
||||
.subdevs = pic64gx_subdevs,
|
||||
};
|
||||
|
||||
static const struct of_device_id mpfs_sys_controller_of_match[] = {
|
||||
{.compatible = "microchip,mpfs-sys-controller", },
|
||||
{.compatible = "microchip,mpfs-sys-controller", .data = &mpfs_config},
|
||||
{.compatible = "microchip,pic64gx-sys-controller", .data = &pic64gx_config},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mpfs_sys_controller_of_match);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user