From 3cf0fba4ff862d833545f82fb2209ff3c79d17b5 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 6 Feb 2020 09:54:49 -0700 Subject: dm: core: Allow iterating devices without uclass_get() At present we have uclass_foreach_dev() which requires that uclass_get() be called beforehand to find the uclass. This is good if we suspect that that function might fail, but often we know that the uclass is available. Add a new helper which does this uclass_get() automatically, so that only the uclass ID is needed. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- include/dm/uclass.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'include') diff --git a/include/dm/uclass.h b/include/dm/uclass.h index 484d1660135..74b8e2ecb5e 100644 --- a/include/dm/uclass.h +++ b/include/dm/uclass.h @@ -365,6 +365,23 @@ int uclass_next_device_check(struct udevice **devp); */ int uclass_resolve_seq(struct udevice *dev); +/** + * uclass_id_foreach_dev() - Helper function to iteration through devices + * + * This creates a for() loop which works through the available devices in + * a uclass ID in order from start to end. + * + * If for some reason the uclass cannot be found, this does nothing. + * + * @id: enum uclass_id ID to use + * @pos: struct udevice * to hold the current device. Set to NULL when there + * are no more devices. + * @uc: temporary uclass variable (struct udevice *) + */ +#define uclass_id_foreach_dev(id, pos, uc) \ + if (!uclass_get(id, &uc)) \ + list_for_each_entry(pos, &uc->dev_head, uclass_node) + /** * uclass_foreach_dev() - Helper function to iteration through devices * -- cgit v1.3.1 From 50162348f0d3b915004733131acd81805e202c76 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 6 Feb 2020 09:54:50 -0700 Subject: dm: core: Add a function to find a device by drvdata It is sometimes useful to find a device in a uclass using only its driver data. The driver data often indicates the 'subtype' of the device, e,g, via its compatible string. Add a function to handle this. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- drivers/core/uclass.c | 17 +++++++++++++++++ include/dm/test.h | 2 ++ include/dm/uclass.h | 14 ++++++++++++++ test/dm/test-fdt.c | 21 +++++++++++++++++++++ 4 files changed, 54 insertions(+) (limited to 'include') diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c index c520ef113a2..61192d8a9ff 100644 --- a/drivers/core/uclass.c +++ b/drivers/core/uclass.c @@ -629,6 +629,23 @@ int uclass_next_device_check(struct udevice **devp) return device_probe(*devp); } +int uclass_first_device_drvdata(enum uclass_id id, ulong driver_data, + struct udevice **devp) +{ + struct udevice *dev; + struct uclass *uc; + + uclass_id_foreach_dev(id, dev, uc) { + if (dev_get_driver_data(dev) == driver_data) { + *devp = dev; + + return device_probe(dev); + } + } + + return -ENODEV; +} + int uclass_bind_device(struct udevice *dev) { struct uclass *uc; diff --git a/include/dm/test.h b/include/dm/test.h index 07385cd531f..f0f36624ce3 100644 --- a/include/dm/test.h +++ b/include/dm/test.h @@ -56,6 +56,8 @@ enum { enum { DM_TEST_TYPE_FIRST = 0, DM_TEST_TYPE_SECOND, + + DM_TEST_TYPE_COUNT, }; /* The number added to the ping total on each probe */ diff --git a/include/dm/uclass.h b/include/dm/uclass.h index 74b8e2ecb5e..70fca79b449 100644 --- a/include/dm/uclass.h +++ b/include/dm/uclass.h @@ -350,6 +350,20 @@ int uclass_first_device_check(enum uclass_id id, struct udevice **devp); */ int uclass_next_device_check(struct udevice **devp); +/** + * uclass_first_device_drvdata() - Find the first device with given driver data + * + * This searches through the devices for a particular uclass looking for one + * that has the given driver data. + * + * @id: Uclass ID to check + * @driver_data: Driver data to search for + * @devp: Returns pointer to the first matching device in that uclass, if found + * @return 0 if found, -ENODEV if not found, other -ve on error + */ +int uclass_first_device_drvdata(enum uclass_id id, ulong driver_data, + struct udevice **devp); + /** * uclass_resolve_seq() - Resolve a device's sequence number * diff --git a/test/dm/test-fdt.c b/test/dm/test-fdt.c index 8ea536c3093..698ca0e7cf8 100644 --- a/test/dm/test-fdt.c +++ b/test/dm/test-fdt.c @@ -893,3 +893,24 @@ static int dm_test_read_int(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_read_int, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + +/* Test iteration through devices by drvdata */ +static int dm_test_uclass_drvdata(struct unit_test_state *uts) +{ + struct udevice *dev; + + ut_assertok(uclass_first_device_drvdata(UCLASS_TEST_FDT, + DM_TEST_TYPE_FIRST, &dev)); + ut_asserteq_str("a-test", dev->name); + + ut_assertok(uclass_first_device_drvdata(UCLASS_TEST_FDT, + DM_TEST_TYPE_SECOND, &dev)); + ut_asserteq_str("d-test", dev->name); + + ut_asserteq(-ENODEV, uclass_first_device_drvdata(UCLASS_TEST_FDT, + DM_TEST_TYPE_COUNT, + &dev)); + + return 0; +} +DM_TEST(dm_test_uclass_drvdata, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); -- cgit v1.3.1 From b4d00b256e3c784de4a33a40f4cd28a94ee2a80c Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 6 Feb 2020 09:54:53 -0700 Subject: x86: Add a clock driver for Intel devices So far we have avoided adding a clock driver for Intel devices. But the Designware I2C driver needs a different clock (133MHz) on Intel devices than on others (166MHz). Add a simple driver that provides this information. This driver can be expanded later as needed. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- drivers/clk/Kconfig | 10 ++++++++ drivers/clk/Makefile | 1 + drivers/clk/intel/Makefile | 6 +++++ drivers/clk/intel/clk_intel.c | 41 +++++++++++++++++++++++++++++++++ include/dt-bindings/clock/intel-clock.h | 15 ++++++++++++ 5 files changed, 73 insertions(+) create mode 100644 drivers/clk/intel/Makefile create mode 100644 drivers/clk/intel/clk_intel.c create mode 100644 include/dt-bindings/clock/intel-clock.h (limited to 'include') diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 16d4237f891..1992d4a4b47 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -73,6 +73,16 @@ config CLK_COMPOSITE_CCF Enable this option if you want to (re-)use the Linux kernel's Common Clock Framework [CCF] composite code in U-Boot's clock driver. +config CLK_INTEL + bool "Enable clock driver for Intel x86" + depends on CLK && X86 + help + This provides very basic support for clocks on Intel SoCs. The driver + is barely used at present but could be expanded as needs arise. + Much clock configuration in U-Boot is either set up by the FSP, or + set up by U-Boot itself but only statically. Thus the driver does not + support changing clock rates, only querying them. + config CLK_STM32F bool "Enable clock driver support for STM32F family" depends on CLK && (STM32F7 || STM32F4) diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 06131edb9fe..e01783391dc 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -25,6 +25,7 @@ obj-$(CONFIG_CLK_MVEBU) += mvebu/ obj-$(CONFIG_CLK_BCM6345) += clk_bcm6345.o obj-$(CONFIG_CLK_BOSTON) += clk_boston.o obj-$(CONFIG_CLK_EXYNOS) += exynos/ +obj-$(CONFIG_$(SPL_TPL_)CLK_INTEL) += intel/ obj-$(CONFIG_CLK_HSDK) += clk-hsdk-cgu.o obj-$(CONFIG_CLK_MPC83XX) += mpc83xx_clk.o obj-$(CONFIG_CLK_OWL) += owl/ diff --git a/drivers/clk/intel/Makefile b/drivers/clk/intel/Makefile new file mode 100644 index 00000000000..45e93d70248 --- /dev/null +++ b/drivers/clk/intel/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright 2010 Google LLC +# + +obj-y += clk_intel.o diff --git a/drivers/clk/intel/clk_intel.c b/drivers/clk/intel/clk_intel.c new file mode 100644 index 00000000000..d2e15491a3d --- /dev/null +++ b/drivers/clk/intel/clk_intel.c @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2019 Google LLC + * Written by Simon Glass + */ + +#include +#include +#include +#include + +static ulong intel_clk_get_rate(struct clk *clk) +{ + ulong rate; + + switch (clk->id) { + case CLK_I2C: + /* Hard-coded to 133MHz on current platforms */ + return 133333333; + default: + return -ENODEV; + } + + return rate; +} + +static struct clk_ops intel_clk_ops = { + .get_rate = intel_clk_get_rate, +}; + +static const struct udevice_id intel_clk_ids[] = { + { .compatible = "intel,apl-clk" }, + { } +}; + +U_BOOT_DRIVER(clk_intel) = { + .name = "clk_intel", + .id = UCLASS_CLK, + .of_match = intel_clk_ids, + .ops = &intel_clk_ops, +}; diff --git a/include/dt-bindings/clock/intel-clock.h b/include/dt-bindings/clock/intel-clock.h new file mode 100644 index 00000000000..e1edd3c71d7 --- /dev/null +++ b/include/dt-bindings/clock/intel-clock.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * This header provides constants for Intel clocks. + * + * The constants defined in this header are used in the device tree + * + * Copyright 2019 Google LLC + */ + +#ifndef _DT_BINDINGS_CLK_INTEL_H +#define _DT_BINDINGS_CLK_INTEL_H + +#define CLK_I2C 1 + +#endif -- cgit v1.3.1 From ba876079714db52887cab9f068ea1136de4cc107 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 6 Feb 2020 09:54:57 -0700 Subject: dm: irq: Add support for interrupt controller types There can be different types of interrupt controllers in a system and some drivers may need to distinguish between these. In general this can be handled using the device tree by adding the interrupt information to device nodes. However on x86 devices we have interrupt controllers which are not tied to any particular device and not really used in U-Boot. These still need to be inited, so a convenient method is to give each controller a type and allow a particular controller type to be probed. Add support for this in sandbox along with a test. Signed-off-by: Simon Glass Reviewed-by: Bin Meng [bmeng: remove the new bland line at EOF of test/dm/irq.c] Signed-off-by: Bin Meng --- arch/sandbox/include/asm/test.h | 4 ++++ drivers/misc/irq-uclass.c | 15 ++++++++++++++- drivers/misc/irq_sandbox.c | 2 +- include/irq.h | 23 +++++++++++++++++++++++ test/dm/irq.c | 13 +++++++++++++ 5 files changed, 55 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/arch/sandbox/include/asm/test.h b/arch/sandbox/include/asm/test.h index 2421922c9ea..7775794eaa8 100644 --- a/arch/sandbox/include/asm/test.h +++ b/arch/sandbox/include/asm/test.h @@ -45,6 +45,10 @@ #define PCI_EA_BAR2_MAGIC 0x72727272 #define PCI_EA_BAR4_MAGIC 0x74747474 +enum { + SANDBOX_IRQN_PEND = 1, /* Interrupt number for 'pending' test */ +}; + /* System controller driver data */ enum { SYSCON0 = 32, diff --git a/drivers/misc/irq-uclass.c b/drivers/misc/irq-uclass.c index d5182cf1497..c52c813ff37 100644 --- a/drivers/misc/irq-uclass.c +++ b/drivers/misc/irq-uclass.c @@ -1,11 +1,13 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * Copyright (C) 2015, Bin Meng + * Copyright 2019 Google, LLC + * Written by Simon Glass */ #include #include #include +#include int irq_route_pmc_gpio_gpe(struct udevice *dev, uint pmc_gpe_num) { @@ -47,6 +49,17 @@ int irq_restore_polarities(struct udevice *dev) return ops->restore_polarities(dev); } +int irq_first_device_type(enum irq_dev_t type, struct udevice **devp) +{ + int ret; + + ret = uclass_first_device_drvdata(UCLASS_IRQ, type, devp); + if (ret) + return log_msg_ret("find", ret); + + return 0; +} + UCLASS_DRIVER(irq) = { .id = UCLASS_IRQ, .name = "irq", diff --git a/drivers/misc/irq_sandbox.c b/drivers/misc/irq_sandbox.c index 6dda1a4c442..011022ac620 100644 --- a/drivers/misc/irq_sandbox.c +++ b/drivers/misc/irq_sandbox.c @@ -43,7 +43,7 @@ static const struct irq_ops sandbox_irq_ops = { }; static const struct udevice_id sandbox_irq_ids[] = { - { .compatible = "sandbox,irq"}, + { .compatible = "sandbox,irq", SANDBOX_IRQT_BASE }, { } }; diff --git a/include/irq.h b/include/irq.h index 01ded64f160..8b4e2ecfc0b 100644 --- a/include/irq.h +++ b/include/irq.h @@ -8,6 +8,17 @@ #ifndef __irq_H #define __irq_H +/* + * Interrupt controller types available. You can find a particular one with + * irq_first_device_type() + */ +enum irq_dev_t { + X86_IRQT_BASE, /* Base controller */ + X86_IRQT_ITSS, /* ITSS controller, e.g. on APL */ + X86_IRQT_ACPI_GPE, /* ACPI General-Purpose Events controller */ + SANDBOX_IRQT_BASE, /* Sandbox testing */ +}; + /** * struct irq_ops - Operations for the IRQ */ @@ -85,4 +96,16 @@ int irq_snapshot_polarities(struct udevice *dev); */ int irq_restore_polarities(struct udevice *dev); +/** + * irq_first_device_type() - Get a particular interrupt controller + * + * On success this returns an activated interrupt device. + * + * @type: Type to find + * @devp: Returns the device, if found + * @return 0 if OK, -ENODEV if not found, other -ve error if uclass failed to + * probe + */ +int irq_first_device_type(enum irq_dev_t type, struct udevice **devp); + #endif diff --git a/test/dm/irq.c b/test/dm/irq.c index 726189c59f7..adbcffbe9c6 100644 --- a/test/dm/irq.c +++ b/test/dm/irq.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -30,3 +31,15 @@ static int dm_test_irq_base(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_irq_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + +/* Test of irq_first_device_type() */ +static int dm_test_irq_type(struct unit_test_state *uts) +{ + struct udevice *dev; + + ut_assertok(irq_first_device_type(SANDBOX_IRQT_BASE, &dev)); + ut_asserteq(-ENODEV, irq_first_device_type(X86_IRQT_BASE, &dev)); + + return 0; +} +DM_TEST(dm_test_irq_type, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); -- cgit v1.3.1 From 025543554c36615a66d66c154f3f763ac788ee15 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 6 Feb 2020 09:55:00 -0700 Subject: dm: irq: Add support for requesting interrupts At present driver model supports the IRQ uclass but there is no way to request a particular interrupt for a driver. Add a mechanism, similar to clock and reset, to read the interrupts required by a device from the device tree and to request those interrupts. U-Boot itself does not have interrupt-driven handlers, so just provide a means to read and clear an interrupt. This can be useful to handle peripherals which must use an interrupt to determine when data is available, for example. Bring over the basic binding file as well, from Linux v5.4. Note that the older binding is not supported in U-Boot; the newer 'special form' must be used. Add a simple test of the new functionality. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- arch/sandbox/dts/test.dts | 5 +- .../interrupt-controller/interrupts.txt | 131 +++++++++++++++++++++ drivers/misc/irq-uclass.c | 116 ++++++++++++++++++ drivers/misc/irq_sandbox.c | 41 +++++++ include/irq.h | 115 ++++++++++++++++++ test/dm/irq.c | 32 +++++ 6 files changed, 439 insertions(+), 1 deletion(-) create mode 100644 doc/device-tree-bindings/interrupt-controller/interrupts.txt (limited to 'include') diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index e529c54d8de..c2284474314 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -93,6 +93,7 @@ <&gpio_b 9 0xc 3 2 1>; int-value = <1234>; uint-value = <(-1234)>; + interrupts-extended = <&irq 3 0>; }; junk { @@ -357,8 +358,10 @@ vss-microvolts = <0>; }; - irq { + irq: irq { compatible = "sandbox,irq"; + interrupt-controller; + #interrupt-cells = <2>; }; lcd { diff --git a/doc/device-tree-bindings/interrupt-controller/interrupts.txt b/doc/device-tree-bindings/interrupt-controller/interrupts.txt new file mode 100644 index 00000000000..38a399a6b1b --- /dev/null +++ b/doc/device-tree-bindings/interrupt-controller/interrupts.txt @@ -0,0 +1,131 @@ +Specifying interrupt information for devices +============================================ + +1) Interrupt client nodes +------------------------- + +Nodes that describe devices which generate interrupts must contain an +"interrupts" property, an "interrupts-extended" property, or both. If both are +present, the latter should take precedence; the former may be provided simply +for compatibility with software that does not recognize the latter. These +properties contain a list of interrupt specifiers, one per output interrupt. The +format of the interrupt specifier is determined by the interrupt controller to +which the interrupts are routed; see section 2 below for details. + + Example: + interrupt-parent = <&intc1>; + interrupts = <5 0>, <6 0>; + +The "interrupt-parent" property is used to specify the controller to which +interrupts are routed and contains a single phandle referring to the interrupt +controller node. This property is inherited, so it may be specified in an +interrupt client node or in any of its parent nodes. Interrupts listed in the +"interrupts" property are always in reference to the node's interrupt parent. + +The "interrupts-extended" property is a special form; useful when a node needs +to reference multiple interrupt parents or a different interrupt parent than +the inherited one. Each entry in this property contains both the parent phandle +and the interrupt specifier. + + Example: + interrupts-extended = <&intc1 5 1>, <&intc2 1 0>; + +(NOTE: only this 'special form' is supported in U-Boot) + + +2) Interrupt controller nodes +----------------------------- + +A device is marked as an interrupt controller with the "interrupt-controller" +property. This is a empty, boolean property. An additional "#interrupt-cells" +property defines the number of cells needed to specify a single interrupt. + +It is the responsibility of the interrupt controller's binding to define the +length and format of the interrupt specifier. The following two variants are +commonly used: + + a) one cell + ----------- + The #interrupt-cells property is set to 1 and the single cell defines the + index of the interrupt within the controller. + + Example: + + vic: intc@10140000 { + compatible = "arm,versatile-vic"; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0x10140000 0x1000>; + }; + + sic: intc@10003000 { + compatible = "arm,versatile-sic"; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0x10003000 0x1000>; + interrupt-parent = <&vic>; + interrupts = <31>; /* Cascaded to vic */ + }; + + b) two cells + ------------ + The #interrupt-cells property is set to 2 and the first cell defines the + index of the interrupt within the controller, while the second cell is used + to specify any of the following flags: + - bits[3:0] trigger type and level flags + 1 = low-to-high edge triggered + 2 = high-to-low edge triggered + 4 = active high level-sensitive + 8 = active low level-sensitive + + Example: + + i2c@7000c000 { + gpioext: gpio-adnp@41 { + compatible = "ad,gpio-adnp"; + reg = <0x41>; + + interrupt-parent = <&gpio>; + interrupts = <160 1>; + + gpio-controller; + #gpio-cells = <1>; + + interrupt-controller; + #interrupt-cells = <2>; + + nr-gpios = <64>; + }; + + sx8634@2b { + compatible = "smtc,sx8634"; + reg = <0x2b>; + + interrupt-parent = <&gpioext>; + interrupts = <3 0x8>; + + #address-cells = <1>; + #size-cells = <0>; + + threshold = <0x40>; + sensitivity = <7>; + }; + }; + + +Example of special form (supported by U-Boot): + + acpi_gpe: general-purpose-events { + reg = ; + compatible = "intel,acpi-gpe"; + interrupt-controller; + #interrupt-cells = <2>; + }; + + tpm@50 { + reg = <0x50>; + compatible = "google,cr50"; + u-boot,i2c-offset-len = <0>; + ready-gpio = <&gpio_n 28 GPIO_ACTIVE_LOW>; + interrupts-extended = <&acpi_gpe 0x3c 0>; + }; diff --git a/drivers/misc/irq-uclass.c b/drivers/misc/irq-uclass.c index c52c813ff37..61aa10e4658 100644 --- a/drivers/misc/irq-uclass.c +++ b/drivers/misc/irq-uclass.c @@ -4,8 +4,11 @@ * Written by Simon Glass */ +#define LOG_CATEGORY UCLASS_IRQ + #include #include +#include #include #include @@ -49,6 +52,119 @@ int irq_restore_polarities(struct udevice *dev) return ops->restore_polarities(dev); } +int irq_read_and_clear(struct irq *irq) +{ + const struct irq_ops *ops = irq_get_ops(irq->dev); + + if (!ops->read_and_clear) + return -ENOSYS; + + return ops->read_and_clear(irq); +} + +#if CONFIG_IS_ENABLED(OF_PLATDATA) +int irq_get_by_index_platdata(struct udevice *dev, int index, + struct phandle_1_arg *cells, struct irq *irq) +{ + int ret; + + if (index != 0) + return -ENOSYS; + ret = uclass_get_device(UCLASS_IRQ, 0, &irq->dev); + if (ret) + return ret; + irq->id = cells[0].arg[0]; + + return 0; +} +#else +static int irq_of_xlate_default(struct irq *irq, + struct ofnode_phandle_args *args) +{ + log_debug("(irq=%p)\n", irq); + + if (args->args_count > 1) { + log_debug("Invaild args_count: %d\n", args->args_count); + return -EINVAL; + } + + if (args->args_count) + irq->id = args->args[0]; + else + irq->id = 0; + + return 0; +} + +static int irq_get_by_index_tail(int ret, ofnode node, + struct ofnode_phandle_args *args, + const char *list_name, int index, + struct irq *irq) +{ + struct udevice *dev_irq; + const struct irq_ops *ops; + + assert(irq); + irq->dev = NULL; + if (ret) + goto err; + + ret = uclass_get_device_by_ofnode(UCLASS_IRQ, args->node, &dev_irq); + if (ret) { + log_debug("uclass_get_device_by_ofnode failed: err=%d\n", ret); + return ret; + } + + irq->dev = dev_irq; + + ops = irq_get_ops(dev_irq); + + if (ops->of_xlate) + ret = ops->of_xlate(irq, args); + else + ret = irq_of_xlate_default(irq, args); + if (ret) { + log_debug("of_xlate() failed: %d\n", ret); + return ret; + } + + return irq_request(dev_irq, irq); +err: + log_debug("Node '%s', property '%s', failed to request IRQ index %d: %d\n", + ofnode_get_name(node), list_name, index, ret); + return ret; +} + +int irq_get_by_index(struct udevice *dev, int index, struct irq *irq) +{ + struct ofnode_phandle_args args; + int ret; + + ret = dev_read_phandle_with_args(dev, "interrupts-extended", + "#interrupt-cells", 0, index, &args); + + return irq_get_by_index_tail(ret, dev_ofnode(dev), &args, + "interrupts-extended", index > 0, irq); +} +#endif /* OF_PLATDATA */ + +int irq_request(struct udevice *dev, struct irq *irq) +{ + const struct irq_ops *ops; + + log_debug("(dev=%p, irq=%p)\n", dev, irq); + if (!irq) + return 0; + ops = irq_get_ops(dev); + + irq->dev = dev; + + if (!ops->request) + return 0; + + return ops->request(irq); +} + int irq_first_device_type(enum irq_dev_t type, struct udevice **devp) { int ret; diff --git a/drivers/misc/irq_sandbox.c b/drivers/misc/irq_sandbox.c index 011022ac620..54bc47c8d8a 100644 --- a/drivers/misc/irq_sandbox.c +++ b/drivers/misc/irq_sandbox.c @@ -8,6 +8,18 @@ #include #include #include +#include + +/** + * struct sandbox_irq_priv - private data for this driver + * + * @count: Counts the number calls to the read_and_clear() method + * @pending: true if an interrupt is pending, else false + */ +struct sandbox_irq_priv { + int count; + bool pending; +}; static int sandbox_set_polarity(struct udevice *dev, uint irq, bool active_low) { @@ -35,11 +47,39 @@ static int sandbox_restore_polarities(struct udevice *dev) return 0; } +static int sandbox_irq_read_and_clear(struct irq *irq) +{ + struct sandbox_irq_priv *priv = dev_get_priv(irq->dev); + + if (irq->id != SANDBOX_IRQN_PEND) + return -EINVAL; + priv->count++; + if (priv->pending) { + priv->pending = false; + return 1; + } + + if (!(priv->count % 3)) + priv->pending = true; + + return 0; +} + +static int sandbox_irq_of_xlate(struct irq *irq, + struct ofnode_phandle_args *args) +{ + irq->id = args->args[0]; + + return 0; +} + static const struct irq_ops sandbox_irq_ops = { .route_pmc_gpio_gpe = sandbox_route_pmc_gpio_gpe, .set_polarity = sandbox_set_polarity, .snapshot_polarities = sandbox_snapshot_polarities, .restore_polarities = sandbox_restore_polarities, + .read_and_clear = sandbox_irq_read_and_clear, + .of_xlate = sandbox_irq_of_xlate, }; static const struct udevice_id sandbox_irq_ids[] = { @@ -52,4 +92,5 @@ U_BOOT_DRIVER(sandbox_irq_drv) = { .id = UCLASS_IRQ, .of_match = sandbox_irq_ids, .ops = &sandbox_irq_ops, + .priv_auto_alloc_size = sizeof(struct sandbox_irq_priv), }; diff --git a/include/irq.h b/include/irq.h index 8b4e2ecfc0b..b71afe9bee9 100644 --- a/include/irq.h +++ b/include/irq.h @@ -19,8 +19,21 @@ enum irq_dev_t { SANDBOX_IRQT_BASE, /* Sandbox testing */ }; +/** + * struct irq - A single irq line handled by an interrupt controller + * + * @dev: IRQ device that handles this irq + * @id: ID to identify this irq with the device + */ +struct irq { + struct udevice *dev; + ulong id; +}; + /** * struct irq_ops - Operations for the IRQ + * + * Each IRQ device can handle mulitple IRQ lines */ struct irq_ops { /** @@ -57,6 +70,55 @@ struct irq_ops { * @return 0 */ int (*restore_polarities)(struct udevice *dev); + + /** + * read_and_clear() - get the value of an interrupt and clear it + * + * Clears the interrupt if pending + * + * @irq: IRQ line + * @return 0 if interrupt is not pending, 1 if it was (and so has been + * cleared), -ve on error + */ + int (*read_and_clear)(struct irq *irq); + /** + * of_xlate - Translate a client's device-tree (OF) irq specifier. + * + * The irq core calls this function as the first step in implementing + * a client's irq_get_by_*() call. + * + * If this function pointer is set to NULL, the irq core will use a + * default implementation, which assumes #interrupt-cells = <1>, and + * that the DT cell contains a simple integer irq ID. + * + * @irq: The irq struct to hold the translation result. + * @args: The irq specifier values from device tree. + * @return 0 if OK, or a negative error code. + */ + int (*of_xlate)(struct irq *irq, struct ofnode_phandle_args *args); + /** + * request - Request a translated irq. + * + * The irq core calls this function as the second step in + * implementing a client's irq_get_by_*() call, following a successful + * xxx_xlate() call, or as the only step in implementing a client's + * irq_request() call. + * + * @irq: The irq struct to request; this has been fille in by + * a previoux xxx_xlate() function call, or by the caller + * of irq_request(). + * @return 0 if OK, or a negative error code. + */ + int (*request)(struct irq *irq); + /** + * free - Free a previously requested irq. + * + * This is the implementation of the client irq_free() API. + * + * @irq: The irq to free. + * @return 0 if OK, or a negative error code. + */ + int (*free)(struct irq *irq); }; #define irq_get_ops(dev) ((struct irq_ops *)(dev)->driver->ops) @@ -96,6 +158,59 @@ int irq_snapshot_polarities(struct udevice *dev); */ int irq_restore_polarities(struct udevice *dev); +/** + * read_and_clear() - get the value of an interrupt and clear it + * + * Clears the interrupt if pending + * + * @dev: IRQ device + * @return 0 if interrupt is not pending, 1 if it was (and so has been + * cleared), -ve on error + */ +int irq_read_and_clear(struct irq *irq); + +/** + * irq_get_by_index - Get/request an irq by integer index. + * + * This looks up and requests an irq. The index is relative to the client + * device; each device is assumed to have n irqs associated with it somehow, + * and this function finds and requests one of them. The mapping of client + * device irq indices to provider irqs may be via device-tree + * properties, board-provided mapping tables, or some other mechanism. + * + * @dev: The client device. + * @index: The index of the irq to request, within the client's list of + * irqs. + * @irq: A pointer to a irq struct to initialise. + * @return 0 if OK, or a negative error code. + */ +int irq_get_by_index(struct udevice *dev, int index, struct irq *irq); + +/** + * irq_request - Request a irq by provider-specific ID. + * + * This requests a irq using a provider-specific ID. Generally, this function + * should not be used, since irq_get_by_index/name() provide an interface that + * better separates clients from intimate knowledge of irq providers. + * However, this function may be useful in core SoC-specific code. + * + * @dev: The irq provider device. + * @irq: A pointer to a irq struct to initialise. The caller must + * have already initialised any field in this struct which the + * irq provider uses to identify the irq. + * @return 0 if OK, or a negative error code. + */ +int irq_request(struct udevice *dev, struct irq *irq); + +/** + * irq_free - Free a previously requested irq. + * + * @irq: A irq struct that was previously successfully requested by + * irq_request/get_by_*(). + * @return 0 if OK, or a negative error code. + */ +int irq_free(struct irq *irq); + /** * irq_first_device_type() - Get a particular interrupt controller * diff --git a/test/dm/irq.c b/test/dm/irq.c index adbcffbe9c6..192d80d7e10 100644 --- a/test/dm/irq.c +++ b/test/dm/irq.c @@ -43,3 +43,35 @@ static int dm_test_irq_type(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_irq_type, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + +/* Test of irq_read_and_clear() */ +static int dm_test_read_and_clear(struct unit_test_state *uts) +{ + struct irq irq; + + ut_assertok(irq_first_device_type(SANDBOX_IRQT_BASE, &irq.dev)); + irq.id = SANDBOX_IRQN_PEND; + ut_asserteq(0, irq_read_and_clear(&irq)); + ut_asserteq(0, irq_read_and_clear(&irq)); + ut_asserteq(0, irq_read_and_clear(&irq)); + ut_asserteq(1, irq_read_and_clear(&irq)); + ut_asserteq(0, irq_read_and_clear(&irq)); + + return 0; +} +DM_TEST(dm_test_read_and_clear, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + +/* Test of irq_request() */ +static int dm_test_request(struct unit_test_state *uts) +{ + struct udevice *dev; + struct irq irq; + + ut_assertok(uclass_first_device_err(UCLASS_TEST_FDT, &dev)); + ut_asserteq_str("a-test", dev->name); + ut_assertok(irq_get_by_index(dev, 0, &irq)); + ut_asserteq(3, irq.id); + + return 0; +} +DM_TEST(dm_test_request, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); -- cgit v1.3.1 From 1400a7f3d3296540bc53ed254515ab06083daff8 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 6 Feb 2020 09:55:03 -0700 Subject: tpm: Add more TPM2 definitions Add definitions for access and status. Need to drop the mixed case. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- include/tpm-v2.h | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'include') diff --git a/include/tpm-v2.h b/include/tpm-v2.h index ae00803f6d9..d53d2e40239 100644 --- a/include/tpm-v2.h +++ b/include/tpm-v2.h @@ -161,6 +161,37 @@ enum tpm_index_attrs { TPMA_NV_AUTHWRITE | TPMA_NV_POLICYWRITE, }; +enum { + TPM_ACCESS_VALID = 1 << 7, + TPM_ACCESS_ACTIVE_LOCALITY = 1 << 5, + TPM_ACCESS_REQUEST_PENDING = 1 << 2, + TPM_ACCESS_REQUEST_USE = 1 << 1, + TPM_ACCESS_ESTABLISHMENT = 1 << 0, +}; + +enum { + TPM_STS_FAMILY_SHIFT = 26, + TPM_STS_FAMILY_MASK = 0x3 << TPM_STS_FAMILY_SHIFT, + TPM_STS_FAMILY_TPM2 = 1 << TPM_STS_FAMILY_SHIFT, + TPM_STS_RESE_TESTABLISMENT_BIT = 1 << 25, + TPM_STS_COMMAND_CANCEL = 1 << 24, + TPM_STS_BURST_COUNT_SHIFT = 8, + TPM_STS_BURST_COUNT_MASK = 0xffff << TPM_STS_BURST_COUNT_SHIFT, + TPM_STS_VALID = 1 << 7, + TPM_STS_COMMAND_READY = 1 << 6, + TPM_STS_GO = 1 << 5, + TPM_STS_DATA_AVAIL = 1 << 4, + TPM_STS_DATA_EXPECT = 1 << 3, + TPM_STS_SELF_TEST_DONE = 1 << 2, + TPM_STS_RESPONSE_RETRY = 1 << 1, +}; + +enum { + TPM_CMD_COUNT_OFFSET = 2, + TPM_CMD_ORDINAL_OFFSET = 6, + TPM_MAX_BUF_SIZE = 1260, +}; + /** * Issue a TPM2_Startup command. * -- cgit v1.3.1