* [PATCH V5 3/3] ARM64 LPC: LPC driver implementation on Hip06
From: Gabriele Paoloni @ 2016-11-25 8:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <4675465.4Qhqy6WU4X@wuerfel>
Hi Arnd
Many thanks for your contribution, much appreciated
I have some comments...see inline below
> -----Original Message-----
> From: Arnd Bergmann [mailto:arnd at arndb.de]
> Sent: 23 November 2016 23:23
> To: linux-arm-kernel at lists.infradead.org
> Cc: Gabriele Paoloni; mark.rutland at arm.com; catalin.marinas at arm.com;
> linux-pci at vger.kernel.org; liviu.dudau at arm.com; Linuxarm;
> lorenzo.pieralisi at arm.com; xuwei (O); Jason Gunthorpe; T homas
> Petazzoni; linux-serial at vger.kernel.org; benh at kernel.crashing.org;
> devicetree at vger.kernel.org; minyard at acm.org; will.deacon at arm.com; John
> Garry; olof at lixom.net; robh+dt at kernel.org; bhelgaas at go og le.com;
> kantyzc at 163.com; zhichang.yuan02 at gmail.com; linux-
> kernel at vger.kernel.org; Yuanzhichang; zourongrong at gmail.com
> Subject: Re: [PATCH V5 3/3] ARM64 LPC: LPC driver implementation on
> Hip06
>
> On Wednesday, November 23, 2016 6:07:11 PM CET Arnd Bergmann wrote:
> > On Wednesday, November 23, 2016 3:22:33 PM CET Gabriele Paoloni
> wrote:
> > > From: Arnd Bergmann [mailto:arnd at arndb.de]
> > > > On Friday, November 18, 2016 5:03:11 PM CET Gabriele Paoloni
> wrote:
> >
> > Please don't proliferate the use of
> > pci_pio_to_address/pci_address_to_pio here, computing the physical
> > address from the logical address is trivial, you just need to
> > subtract the start of the range that you already use when matching
> > the port number range.
> >
> > The only thing we need here is to make of_address_to_resource()
> > return the correct logical port number that was registered for
> > a given host device when asked to translate an address that
> > does not have a CPU address associated with it.
>
> Ok, I admit this was a little harder than I expected, but see below
> for a rough outline of how I think it can be done.
>
> This makes it possible to translate bus specific I/O port numbers
> from device nodes into Linux port numbers, and gives a way to register
> them. We could take this further and completely remove
> pci_pio_to_address
> and pci_address_to_pio if we make the I/O port translation always
> go through the io_range list, looking up up the hostbridge by fwnode,
> but we don't have to do that now.
>
> The patch is completely untested and probably buggy, it just seemed
> easier to put out a prototype than to keep going in circles with the
> discussion.
>
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
>
> diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
> index bf601d4df8cf..6cadf0501bb0 100644
> --- a/drivers/acpi/pci_root.c
> +++ b/drivers/acpi/pci_root.c
> @@ -730,7 +730,8 @@ static void acpi_pci_root_validate_resources(struct
> device *dev,
> }
> }
>
> -static void acpi_pci_root_remap_iospace(struct resource_entry *entry)
> +static void acpi_pci_root_remap_iospace(struct fwnode_handle *node,
> + struct resource_entry *entry)
> {
> #ifdef PCI_IOBASE
> struct resource *res = entry->res;
> @@ -739,11 +740,7 @@ static void acpi_pci_root_remap_iospace(struct
> resource_entry *entry)
> resource_size_t length = resource_size(res);
> unsigned long port;
>
> - if (pci_register_io_range(cpu_addr, length))
> - goto err;
> -
> - port = pci_address_to_pio(cpu_addr);
> - if (port == (unsigned long)-1)
> + if (pci_register_io_range(node, cpu_addr, length, &port))
> goto err;
>
> res->start = port;
> @@ -781,7 +778,8 @@ int acpi_pci_probe_root_resources(struct
> acpi_pci_root_info *info)
> else {
> resource_list_for_each_entry_safe(entry, tmp, list) {
> if (entry->res->flags & IORESOURCE_IO)
> - acpi_pci_root_remap_iospace(entry);
> + acpi_pci_root_remap_iospace(&device->fwnode,
> + entry);
>
> if (entry->res->flags & IORESOURCE_DISABLED)
> resource_list_destroy_entry(entry);
> diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
> index a50025a3777f..df96955a43f8 100644
> --- a/drivers/block/nbd.c
> +++ b/drivers/block/nbd.c
> @@ -760,8 +760,10 @@ static int __nbd_ioctl(struct block_device *bdev,
> struct nbd_device *nbd,
> set_bit(NBD_RUNNING, &nbd->runtime_flags);
> blk_mq_update_nr_hw_queues(&nbd->tag_set, nbd-
> >num_connections);
> args = kcalloc(num_connections, sizeof(*args), GFP_KERNEL);
> - if (!args)
> + if (!args) {
> + error = -ENOMEM;
> goto out_err;
> + }
> nbd->task_recv = current;
> mutex_unlock(&nbd->config_lock);
>
> diff --git a/drivers/of/address.c b/drivers/of/address.c
> index 02b2903fe9d2..5decaba96eed 100644
> --- a/drivers/of/address.c
> +++ b/drivers/of/address.c
> @@ -2,6 +2,7 @@
> #define pr_fmt(fmt) "OF: " fmt
>
> #include <linux/device.h>
> +#include <linux/fwnode.h>
> #include <linux/io.h>
> #include <linux/ioport.h>
> #include <linux/module.h>
> @@ -323,14 +324,9 @@ int of_pci_range_to_resource(struct of_pci_range
> *range,
>
> if (res->flags & IORESOURCE_IO) {
> unsigned long port;
> - err = pci_register_io_range(range->cpu_addr, range->size);
> + err = pci_register_io_range(&np->fwnode, range->cpu_addr,
> range->size, &port);
> if (err)
> goto invalid_range;
> - port = pci_address_to_pio(range->cpu_addr);
> - if (port == (unsigned long)-1) {
> - err = -EINVAL;
> - goto invalid_range;
> - }
> res->start = port;
> } else {
> if ((sizeof(resource_size_t) < 8) &&
> @@ -479,7 +475,7 @@ static int of_empty_ranges_quirk(struct device_node
> *np)
> return false;
> }
>
> -static int of_translate_one(struct device_node *parent, struct of_bus
> *bus,
> +static u64 of_translate_one(struct device_node *parent, struct of_bus
> *bus,
> struct of_bus *pbus, __be32 *addr,
> int na, int ns, int pna, const char *rprop)
> {
> @@ -507,7 +503,7 @@ static int of_translate_one(struct device_node
> *parent, struct of_bus *bus,
> ranges = of_get_property(parent, rprop, &rlen);
> if (ranges == NULL && !of_empty_ranges_quirk(parent)) {
> pr_debug("no ranges; cannot translate\n");
> - return 1;
> + return OF_BAD_ADDR;
> }
> if (ranges == NULL || rlen == 0) {
> offset = of_read_number(addr, na);
> @@ -528,7 +524,7 @@ static int of_translate_one(struct device_node
> *parent, struct of_bus *bus,
> }
> if (offset == OF_BAD_ADDR) {
> pr_debug("not found !\n");
> - return 1;
> + return offset;
> }
> memcpy(addr, ranges + na, 4 * pna);
>
> @@ -537,7 +533,10 @@ static int of_translate_one(struct device_node
> *parent, struct of_bus *bus,
> pr_debug("with offset: %llx\n", (unsigned long long)offset);
>
> /* Translate it into parent bus space */
> - return pbus->translate(addr, offset, pna);
> + if (pbus->translate(addr, offset, pna))
> + return OF_BAD_ADDR;
> +
> + return offset;
> }
>
> /*
> @@ -549,9 +548,14 @@ static int of_translate_one(struct device_node
> *parent, struct of_bus *bus,
> * that translation is impossible (that is we are not dealing with a
> value
> * that can be mapped to a cpu physical address). This is not really
> specified
> * that way, but this is traditionally the way IBM at least do things
> + *
> + * Whenever the translation fails, the *host pointer will be set to
> the
> + * device that lacks a tranlation, and the return code is relative to
> + * that node.
This seems to be wrong to me. We are abusing of the error conditions.
So effectively if there is a buggy DT for an IO resource we end up
assuming that we are using a special IO device with unmapped addresses.
The patch at the bottom apply on top of this one and I think is a more
reasonable approach
> */
> static u64 __of_translate_address(struct device_node *dev,
> - const __be32 *in_addr, const char *rprop)
> + const __be32 *in_addr, const char *rprop,
> + struct device_node **host)
> {
> struct device_node *parent = NULL;
> struct of_bus *bus, *pbus;
> @@ -564,6 +568,7 @@ static u64 __of_translate_address(struct
> device_node *dev,
> /* Increase refcount at current level */
> of_node_get(dev);
>
> + *host = NULL;
> /* Get parent & match bus type */
> parent = of_get_parent(dev);
> if (parent == NULL)
> @@ -600,8 +605,9 @@ static u64 __of_translate_address(struct
> device_node *dev,
> pbus = of_match_bus(parent);
> pbus->count_cells(dev, &pna, &pns);
> if (!OF_CHECK_COUNTS(pna, pns)) {
> - pr_err("Bad cell count for %s\n",
> - of_node_full_name(dev));
> + pr_debug("Bad cell count for %s\n",
> + of_node_full_name(dev));
> + *host = of_node_get(parent);
> break;
> }
>
> @@ -609,7 +615,9 @@ static u64 __of_translate_address(struct
> device_node *dev,
> pbus->name, pna, pns, of_node_full_name(parent));
>
> /* Apply bus translation */
> - if (of_translate_one(dev, bus, pbus, addr, na, ns, pna,
> rprop))
> + result = of_translate_one(dev, bus, pbus, addr, na, ns,
> + pna, rprop);
> + if (result == OF_BAD_ADDR)
It seems to me that here you missed "*host = of_node_get(parent);"..?
> break;
>
> /* Complete the move up one level */
> @@ -628,13 +636,32 @@ static u64 __of_translate_address(struct
> device_node *dev,
>
> u64 of_translate_address(struct device_node *dev, const __be32
> *in_addr)
> {
> - return __of_translate_address(dev, in_addr, "ranges");
> + struct device_node *host;
> + u64 ret;
> +
> + ret = __of_translate_address(dev, in_addr, "ranges", &host);
> + if (host) {
> + of_node_put(host);
> + return OF_BAD_ADDR;
> + }
> +
> + return ret;
> }
> EXPORT_SYMBOL(of_translate_address);
>
> u64 of_translate_dma_address(struct device_node *dev, const __be32
> *in_addr)
> {
> - return __of_translate_address(dev, in_addr, "dma-ranges");
> + struct device_node *host;
> + u64 ret;
> +
> + ret = __of_translate_address(dev, in_addr, "dma-ranges", &host);
> +
> + if (host) {
> + of_node_put(host);
> + return OF_BAD_ADDR;
> + }
> +
> + return ret;
> }
> EXPORT_SYMBOL(of_translate_dma_address);
>
> @@ -676,29 +703,48 @@ const __be32 *of_get_address(struct device_node
> *dev, int index, u64 *size,
> }
> EXPORT_SYMBOL(of_get_address);
>
> +extern unsigned long extio_translate(struct fwnode_handle *node,
> unsigned long offset);
> +
> +u64 of_translate_ioport(struct device_node *dev, const __be32
> *in_addr)
> +{
> + u64 taddr;
> + unsigned long port;
> + struct device_node *host;
> +
> + taddr = __of_translate_address(dev, in_addr, "ranges", &host);
> + if (host) {
> + /* host specific port access */
> + port = extio_translate(&host->fwnode, taddr);
> + of_node_put(host);
> + } else {
> + /* memory mapped I/O range */
> + port = pci_address_to_pio(taddr);
> + if (port == (unsigned long)-1)
> + return OF_BAD_ADDR;
> + }
> +
> + return port;
> +}
> +
> static int __of_address_to_resource(struct device_node *dev,
> const __be32 *addrp, u64 size, unsigned int flags,
> const char *name, struct resource *r)
> {
> u64 taddr;
>
> - if ((flags & (IORESOURCE_IO | IORESOURCE_MEM)) == 0)
> + if (flags & IORESOURCE_MEM)
> + taddr = of_translate_address(dev, addrp);
> + else if (flags & IORESOURCE_IO)
> + taddr = of_translate_ioport(dev, addrp);
> + else
> return -EINVAL;
> - taddr = of_translate_address(dev, addrp);
> +
> if (taddr == OF_BAD_ADDR)
> return -EINVAL;
> memset(r, 0, sizeof(struct resource));
> - if (flags & IORESOURCE_IO) {
> - unsigned long port;
> - port = pci_address_to_pio(taddr);
> - if (port == (unsigned long)-1)
> - return -EINVAL;
> - r->start = port;
> - r->end = port + size - 1;
> - } else {
> - r->start = taddr;
> - r->end = taddr + size - 1;
> - }
> +
> + r->start = taddr;
> + r->end = taddr + size - 1;
> r->flags = flags;
> r->name = name ? name : dev->full_name;
>
> diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> index eda6a7cf0e54..320ab9fbf6af 100644
> --- a/drivers/pci/pci.c
> +++ b/drivers/pci/pci.c
> @@ -3249,6 +3249,7 @@ EXPORT_SYMBOL(pci_request_regions_exclusive);
> #ifdef PCI_IOBASE
> struct io_range {
> struct list_head list;
> + struct fwnode_handle *node;
> phys_addr_t start;
> resource_size_t size;
> };
> @@ -3257,11 +3258,14 @@ static LIST_HEAD(io_range_list);
> static DEFINE_SPINLOCK(io_range_lock);
> #endif
>
> +#define IO_RANGE_IOEXT (resource_size_t)(-1ull)
> +
> /*
> * Record the PCI IO range (expressed as CPU physical address + size).
> * Return a negative value if an error has occured, zero otherwise
> */
> -int __weak pci_register_io_range(phys_addr_t addr, resource_size_t
> size)
> +int __weak pci_register_io_range(struct fwnode_handle *node,
> phys_addr_t addr,
> + resource_size_t size, unsigned long *port)
> {
> int err = 0;
>
> @@ -3272,7 +3276,12 @@ int __weak pci_register_io_range(phys_addr_t
> addr, resource_size_t size)
> /* check if the range hasn't been previously recorded */
> spin_lock(&io_range_lock);
> list_for_each_entry(range, &io_range_list, list) {
> - if (addr >= range->start && addr + size <= range->start +
> size) {
> + if (node == range->node)
> + goto end_register;
> +
It seems to me that the condition above is sufficient; i.e.
we can remove the one here below...?
> + if (addr != IO_RANGE_IOEXT &&
> + addr >= range->start &&
> + addr + size <= range->start + size) {
> /* range already registered, bail out */
> goto end_register;
> }
> @@ -3298,6 +3307,7 @@ int __weak pci_register_io_range(phys_addr_t
> addr, resource_size_t size)
> goto end_register;
> }
>
> + range->node = node;
> range->start = addr;
> range->size = size;
>
> @@ -3305,11 +3315,26 @@ int __weak pci_register_io_range(phys_addr_t
> addr, resource_size_t size)
>
> end_register:
> spin_unlock(&io_range_lock);
> +
> + *port = allocated_size;
> +#else
> + /*
> + * powerpc and microblaze have their own registration,
> + * just look up the value here
> + */
> + *port = pci_address_to_pio(addr);
> #endif
>
> return err;
> }
>
> +#ifdef CONFIG_IOEXT
> +int ioext_register_io_range
> +{
> + return pci_register_io_range(node, IO_RANGE_IOEXT, size, port);
> +}
> +#endif
> +
> phys_addr_t pci_pio_to_address(unsigned long pio)
> {
> phys_addr_t address = (phys_addr_t)OF_BAD_ADDR;
> diff --git a/include/linux/pci.h b/include/linux/pci.h
> index 6bd94a803e8f..b7a8fa3da3ca 100644
> --- a/include/linux/pci.h
> +++ b/include/linux/pci.h
> @@ -1192,7 +1192,8 @@ int __must_check pci_bus_alloc_resource(struct
> pci_bus *bus,
> void *alignf_data);
>
>
> -int pci_register_io_range(phys_addr_t addr, resource_size_t size);
> +int pci_register_io_range(struct fwnode_handle *node, phys_addr_t
> addr,
> + resource_size_t size, unsigned long *port);
> unsigned long pci_address_to_pio(phys_addr_t addr);
> phys_addr_t pci_pio_to_address(unsigned long pio);
> int pci_remap_iospace(const struct resource *res, phys_addr_t
> phys_addr);
I think the patch below is a more reasonable approach to identify
a host that does not support address translation and it should
guarantee safety against broken DTs...
diff --git a/drivers/of/address.c b/drivers/of/address.c
index 5decaba..9bfc526 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -540,6 +540,49 @@ static u64 of_translate_one(struct device_node *parent, struct of_bus *bus,
}
Signed-off-by: Zhichang Yuan <yuanzhichang@hisilicon.com>
Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
/*
+ * of_isa_indirect_io - get the IO address from some isa reg property value.
+ * For some isa/lpc devices, no ranges property in ancestor node.
+ * The device addresses are described directly in their regs property.
+ * This fixup function will be called to get the IO address of isa/lpc
+ * devices when the normal of_translation failed.
+ *
+ * @parent: points to the parent dts node;
+ * @bus: points to the of_bus which can be used to parse address;
+ * @addr: the address from reg property;
+ * @na: the address cell counter of @addr;
+ * @presult: store the address paresed from @addr;
+ *
+ * return 1 when successfully get the I/O address;
+ * 0 will return for some failures.
+ */
+static int of_get_isa_indirect_io(struct device_node *parent,
+ struct of_bus *bus, __be32 *addr,
+ int na, u64 *presult)
+{
+ unsigned int flags;
+ unsigned int rlen;
+
+ /* whether support indirectIO */
+ if (!indirect_io_enabled())
+ return 0;
+
+ if (!of_bus_isa_match(parent))
+ return 0;
+
+ flags = bus->get_flags(addr);
+ if (!(flags & IORESOURCE_IO))
+ return 0;
+
+ /* there is ranges property, apply the normal translation directly. */
+ if (of_get_property(parent, "ranges", &rlen))
+ return 0;
+
+ *presult = of_read_number(addr + 1, na - 1);
+ /* this fixup is only valid for specific I/O range. */
+ return addr_is_indirect_io(*presult);
+}
+
+/*
* Translate an address from the device-tree into a CPU physical address,
* this walks up the tree and applies the various bus mappings on the
* way.
@@ -600,14 +643,23 @@ static u64 __of_translate_address(struct device_node *dev,
result = of_read_number(addr, na);
break;
}
+ /*
+ * For indirectIO device which has no ranges property, get
+ * the address from reg directly.
+ */
+ if (of_get_isa_indirect_io(dev, bus, addr, na, &result)) {
+ pr_debug("isa indirectIO matched(%s)..addr = 0x%llx\n",
+ of_node_full_name(dev), result);
+ *host = of_node_get(parent);
+ break;
+ }
/* Get new parent bus and counts */
pbus = of_match_bus(parent);
pbus->count_cells(dev, &pna, &pns);
if (!OF_CHECK_COUNTS(pna, pns)) {
- pr_debug("Bad cell count for %s\n",
+ pr_err("Bad cell count for %s\n",
of_node_full_name(dev));
- *host = of_node_get(parent);
break;
}
diff --git a/include/linux/of_address.h b/include/linux/of_address.h
index 3786473..14848d8 100644
--- a/include/linux/of_address.h
+++ b/include/linux/of_address.h
@@ -24,6 +24,23 @@ struct of_pci_range {
#define for_each_of_pci_range(parser, range) \
for (; of_pci_range_parser_one(parser, range);)
+#ifndef indirect_io_enabled
+#define indirect_io_enabled indirect_io_enabled
+static inline bool indirect_io_enabled(void)
+{
+ return false;
+}
+#endif
+
+#ifndef addr_is_indirect_io
+#define addr_is_indirect_io addr_is_indirect_io
+static inline int addr_is_indirect_io(u64 taddr)
+{
+ return 0;
+}
+#endif
+
+
/* Translate a DMA address from device space to CPU space */
extern u64 of_translate_dma_address(struct device_node *dev,
const __be32 *in_addr);
--
2.7.4
^ permalink raw reply related
* [PATCH v17 03/15] clocksource/drivers/arm_arch_timer: Improve printk relevant code
From: fu.wei at linaro.org @ 2016-11-25 8:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161125084623.22515-1-fu.wei@linaro.org>
From: Fu Wei <fu.wei@linaro.org>
This patch defines pr_fmt(fmt) for all pr_* functions,
then the pr_* doesn't need to add "arch_timer:" everytime.
According to the suggestion from checkpatch.pl:
(1) delete some Blank Spaces in arch_timer_banner;
(2) delete a redundant Tab in a bland line of arch_timer_init(void)
No functional change.
Signed-off-by: Fu Wei <fu.wei@linaro.org>
Acked-by: Mark Rutland <mark.rutland@arm.com>
Tested-by: Xiongfeng Wang <wangxiongfeng2@huawei.com>
---
drivers/clocksource/arm_arch_timer.c | 49 ++++++++++++++++++------------------
1 file changed, 25 insertions(+), 24 deletions(-)
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 63bb532..15341cf 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -32,6 +32,9 @@
#include <clocksource/arm_arch_timer.h>
+#undef pr_fmt
+#define pr_fmt(fmt) "arch_timer: " fmt
+
#define CNTTIDR 0x08
#define CNTTIDR_VIRT(n) (BIT(1) << ((n) * 4))
@@ -504,22 +507,22 @@ arch_timer_detect_rate(void __iomem *cntbase, struct device_node *np)
/* Check the timer frequency. */
if (arch_timer_rate == 0)
- pr_warn("Architected timer frequency not available\n");
+ pr_warn("frequency not available\n");
}
static void arch_timer_banner(unsigned type)
{
- pr_info("Architected %s%s%s timer(s) running at %lu.%02luMHz (%s%s%s).\n",
- type & ARCH_CP15_TIMER ? "cp15" : "",
- type == (ARCH_CP15_TIMER | ARCH_MEM_TIMER) ? " and " : "",
- type & ARCH_MEM_TIMER ? "mmio" : "",
- (unsigned long)arch_timer_rate / 1000000,
- (unsigned long)(arch_timer_rate / 10000) % 100,
- type & ARCH_CP15_TIMER ?
- (arch_timer_uses_ppi == VIRT_PPI) ? "virt" : "phys" :
+ pr_info("%s%s%s timer(s) running@%lu.%02luMHz (%s%s%s).\n",
+ type & ARCH_CP15_TIMER ? "cp15" : "",
+ type == (ARCH_CP15_TIMER | ARCH_MEM_TIMER) ? " and " : "",
+ type & ARCH_MEM_TIMER ? "mmio" : "",
+ (unsigned long)arch_timer_rate / 1000000,
+ (unsigned long)(arch_timer_rate / 10000) % 100,
+ type & ARCH_CP15_TIMER ?
+ (arch_timer_uses_ppi == VIRT_PPI) ? "virt" : "phys" :
"",
- type == (ARCH_CP15_TIMER | ARCH_MEM_TIMER) ? "/" : "",
- type & ARCH_MEM_TIMER ?
+ type == (ARCH_CP15_TIMER | ARCH_MEM_TIMER) ? "/" : "",
+ type & ARCH_MEM_TIMER ?
arch_timer_mem_use_virtual ? "virt" : "phys" :
"");
}
@@ -618,8 +621,7 @@ static void __init arch_counter_register(unsigned type)
static void arch_timer_stop(struct clock_event_device *clk)
{
- pr_debug("arch_timer_teardown disable IRQ%d cpu #%d\n",
- clk->irq, smp_processor_id());
+ pr_debug("disable IRQ%d cpu #%d\n", clk->irq, smp_processor_id());
disable_percpu_irq(arch_timer_ppi[arch_timer_uses_ppi]);
if (arch_timer_has_nonsecure_ppi())
@@ -712,8 +714,7 @@ static int __init arch_timer_register(void)
}
if (err) {
- pr_err("arch_timer: can't register interrupt %d (%d)\n",
- ppi, err);
+ pr_err("can't register interrupt %d (%d)\n", ppi, err);
goto out_free;
}
@@ -766,7 +767,7 @@ static int __init arch_timer_mem_register(void __iomem *base, unsigned int irq)
ret = request_irq(irq, func, IRQF_TIMER, "arch_mem_timer", &t->evt);
if (ret) {
- pr_err("arch_timer: Failed to request mem timer irq\n");
+ pr_err("Failed to request mem timer irq\n");
kfree(t);
}
@@ -844,7 +845,7 @@ static int __init arch_timer_init(void)
}
if (!has_ppi) {
- pr_warn("arch_timer: No interrupt available, giving up\n");
+ pr_warn("No interrupt available, giving up\n");
return -EINVAL;
}
}
@@ -858,7 +859,7 @@ static int __init arch_timer_init(void)
return ret;
arch_timer_kvm_info.virtual_irq = arch_timer_ppi[VIRT_PPI];
-
+
return 0;
}
@@ -867,7 +868,7 @@ static int __init arch_timer_of_init(struct device_node *np)
int i;
if (arch_timers_present & ARCH_CP15_TIMER) {
- pr_warn("arch_timer: multiple nodes in dt, skipping\n");
+ pr_warn("multiple nodes in dt, skipping\n");
return 0;
}
@@ -911,7 +912,7 @@ static int __init arch_timer_mem_init(struct device_node *np)
arch_timers_present |= ARCH_MEM_TIMER;
cntctlbase = of_iomap(np, 0);
if (!cntctlbase) {
- pr_err("arch_timer: Can't find CNTCTLBase\n");
+ pr_err("Can't find CNTCTLBase\n");
return -ENXIO;
}
@@ -926,7 +927,7 @@ static int __init arch_timer_mem_init(struct device_node *np)
u32 cntacr;
if (of_property_read_u32(frame, "frame-number", &n)) {
- pr_err("arch_timer: Missing frame-number\n");
+ pr_err("Missing frame-number\n");
of_node_put(frame);
goto out;
}
@@ -955,7 +956,7 @@ static int __init arch_timer_mem_init(struct device_node *np)
ret= -ENXIO;
base = arch_counter_base = of_iomap(best_frame, 0);
if (!base) {
- pr_err("arch_timer: Can't map frame's registers\n");
+ pr_err("Can't map frame's registers\n");
goto out;
}
@@ -966,7 +967,7 @@ static int __init arch_timer_mem_init(struct device_node *np)
ret = -EINVAL;
if (!irq) {
- pr_err("arch_timer: Frame missing %s irq",
+ pr_err("Frame missing %s irq",
arch_timer_mem_use_virtual ? "virt" : "phys");
goto out;
}
@@ -1008,7 +1009,7 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table)
struct acpi_table_gtdt *gtdt;
if (arch_timers_present & ARCH_CP15_TIMER) {
- pr_warn("arch_timer: already initialized, skipping\n");
+ pr_warn("already initialized, skipping\n");
return -EINVAL;
}
--
2.9.3
^ permalink raw reply related
* [PATCH v17 04/15] clocksource/drivers/arm_arch_timer: rename some enums and defines.
From: fu.wei at linaro.org @ 2016-11-25 8:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161125084623.22515-1-fu.wei@linaro.org>
From: Fu Wei <fu.wei@linaro.org>
Rename some enums and defines, to unify the format of enums and defines
in arm_arch_timer.h, also update all the users of these enums and defines:
drivers/clocksource/arm_arch_timer.c
virt/kvm/arm/hyp/timer-sr.c
No functional change.
Signed-off-by: Fu Wei <fu.wei@linaro.org>
Tested-by: Xiongfeng Wang <wangxiongfeng2@huawei.com>
---
drivers/clocksource/arm_arch_timer.c | 111 ++++++++++++++++++-----------------
include/clocksource/arm_arch_timer.h | 24 ++++----
virt/kvm/arm/hyp/timer-sr.c | 6 +-
3 files changed, 73 insertions(+), 68 deletions(-)
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 15341cf..231175b 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -66,11 +66,11 @@ struct arch_timer {
#define to_arch_timer(e) container_of(e, struct arch_timer, evt)
static u32 arch_timer_rate;
-static int arch_timer_ppi[MAX_TIMER_PPI];
+static int arch_timer_ppi[ARCH_TIMER_MAX_TIMER_PPI];
static struct clock_event_device __percpu *arch_timer_evt;
-static enum arch_timer_ppi_nr arch_timer_uses_ppi = VIRT_PPI;
+static enum arch_timer_ppi_nr arch_timer_uses_ppi = ARCH_TIMER_VIRT_PPI;
static bool arch_timer_c3stop;
static bool arch_timer_mem_use_virtual;
@@ -340,7 +340,7 @@ static void fsl_a008585_set_sne(struct clock_event_device *clk)
if (!static_branch_unlikely(&arch_timer_read_ool_enabled))
return;
- if (arch_timer_uses_ppi == VIRT_PPI)
+ if (arch_timer_uses_ppi == ARCH_TIMER_VIRT_PPI)
clk->set_next_event = fsl_a008585_set_next_event_virt;
else
clk->set_next_event = fsl_a008585_set_next_event_phys;
@@ -352,7 +352,7 @@ static void __arch_timer_setup(unsigned type,
{
clk->features = CLOCK_EVT_FEAT_ONESHOT;
- if (type == ARCH_CP15_TIMER) {
+ if (type == ARCH_TIMER_TYPE_CP15) {
if (arch_timer_c3stop)
clk->features |= CLOCK_EVT_FEAT_C3STOP;
clk->name = "arch_sys_timer";
@@ -360,14 +360,14 @@ static void __arch_timer_setup(unsigned type,
clk->cpumask = cpumask_of(smp_processor_id());
clk->irq = arch_timer_ppi[arch_timer_uses_ppi];
switch (arch_timer_uses_ppi) {
- case VIRT_PPI:
+ case ARCH_TIMER_VIRT_PPI:
clk->set_state_shutdown = arch_timer_shutdown_virt;
clk->set_state_oneshot_stopped = arch_timer_shutdown_virt;
clk->set_next_event = arch_timer_set_next_event_virt;
break;
- case PHYS_SECURE_PPI:
- case PHYS_NONSECURE_PPI:
- case HYP_PPI:
+ case ARCH_TIMER_PHYS_SECURE_PPI:
+ case ARCH_TIMER_PHYS_NONSECURE_PPI:
+ case ARCH_TIMER_HYP_PPI:
clk->set_state_shutdown = arch_timer_shutdown_phys;
clk->set_state_oneshot_stopped = arch_timer_shutdown_phys;
clk->set_next_event = arch_timer_set_next_event_phys;
@@ -447,8 +447,8 @@ static void arch_counter_set_user_access(void)
static bool arch_timer_has_nonsecure_ppi(void)
{
- return (arch_timer_uses_ppi == PHYS_SECURE_PPI &&
- arch_timer_ppi[PHYS_NONSECURE_PPI]);
+ return (arch_timer_uses_ppi == ARCH_TIMER_PHYS_SECURE_PPI &&
+ arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI]);
}
static u32 check_ppi_trigger(int irq)
@@ -469,14 +469,15 @@ static int arch_timer_starting_cpu(unsigned int cpu)
struct clock_event_device *clk = this_cpu_ptr(arch_timer_evt);
u32 flags;
- __arch_timer_setup(ARCH_CP15_TIMER, clk);
+ __arch_timer_setup(ARCH_TIMER_TYPE_CP15, clk);
flags = check_ppi_trigger(arch_timer_ppi[arch_timer_uses_ppi]);
enable_percpu_irq(arch_timer_ppi[arch_timer_uses_ppi], flags);
if (arch_timer_has_nonsecure_ppi()) {
- flags = check_ppi_trigger(arch_timer_ppi[PHYS_NONSECURE_PPI]);
- enable_percpu_irq(arch_timer_ppi[PHYS_NONSECURE_PPI], flags);
+ flags = check_ppi_trigger(arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI]);
+ enable_percpu_irq(arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI],
+ flags);
}
arch_counter_set_user_access();
@@ -513,16 +514,17 @@ arch_timer_detect_rate(void __iomem *cntbase, struct device_node *np)
static void arch_timer_banner(unsigned type)
{
pr_info("%s%s%s timer(s) running at %lu.%02luMHz (%s%s%s).\n",
- type & ARCH_CP15_TIMER ? "cp15" : "",
- type == (ARCH_CP15_TIMER | ARCH_MEM_TIMER) ? " and " : "",
- type & ARCH_MEM_TIMER ? "mmio" : "",
+ type & ARCH_TIMER_TYPE_CP15 ? "cp15" : "",
+ type == (ARCH_TIMER_TYPE_CP15 | ARCH_TIMER_TYPE_MEM) ?
+ " and " : "",
+ type & ARCH_TIMER_TYPE_MEM ? "mmio" : "",
(unsigned long)arch_timer_rate / 1000000,
(unsigned long)(arch_timer_rate / 10000) % 100,
- type & ARCH_CP15_TIMER ?
- (arch_timer_uses_ppi == VIRT_PPI) ? "virt" : "phys" :
+ type & ARCH_TIMER_TYPE_CP15 ?
+ (arch_timer_uses_ppi == ARCH_TIMER_VIRT_PPI) ? "virt" : "phys" :
"",
- type == (ARCH_CP15_TIMER | ARCH_MEM_TIMER) ? "/" : "",
- type & ARCH_MEM_TIMER ?
+ type == (ARCH_TIMER_TYPE_CP15 | ARCH_TIMER_TYPE_MEM) ? "/" : "",
+ type & ARCH_TIMER_TYPE_MEM ?
arch_timer_mem_use_virtual ? "virt" : "phys" :
"");
}
@@ -588,8 +590,9 @@ static void __init arch_counter_register(unsigned type)
u64 start_count;
/* Register the CP15 based counter if we have one */
- if (type & ARCH_CP15_TIMER) {
- if (IS_ENABLED(CONFIG_ARM64) || arch_timer_uses_ppi == VIRT_PPI)
+ if (type & ARCH_TIMER_TYPE_CP15) {
+ if (IS_ENABLED(CONFIG_ARM64) ||
+ arch_timer_uses_ppi == ARCH_TIMER_VIRT_PPI)
arch_timer_read_counter = arch_counter_get_cntvct;
else
arch_timer_read_counter = arch_counter_get_cntpct;
@@ -625,7 +628,7 @@ static void arch_timer_stop(struct clock_event_device *clk)
disable_percpu_irq(arch_timer_ppi[arch_timer_uses_ppi]);
if (arch_timer_has_nonsecure_ppi())
- disable_percpu_irq(arch_timer_ppi[PHYS_NONSECURE_PPI]);
+ disable_percpu_irq(arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI]);
clk->set_state_shutdown(clk);
}
@@ -688,24 +691,24 @@ static int __init arch_timer_register(void)
ppi = arch_timer_ppi[arch_timer_uses_ppi];
switch (arch_timer_uses_ppi) {
- case VIRT_PPI:
+ case ARCH_TIMER_VIRT_PPI:
err = request_percpu_irq(ppi, arch_timer_handler_virt,
"arch_timer", arch_timer_evt);
break;
- case PHYS_SECURE_PPI:
- case PHYS_NONSECURE_PPI:
+ case ARCH_TIMER_PHYS_SECURE_PPI:
+ case ARCH_TIMER_PHYS_NONSECURE_PPI:
err = request_percpu_irq(ppi, arch_timer_handler_phys,
"arch_timer", arch_timer_evt);
- if (!err && arch_timer_ppi[PHYS_NONSECURE_PPI]) {
- ppi = arch_timer_ppi[PHYS_NONSECURE_PPI];
+ if (!err && arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI]) {
+ ppi = arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI];
err = request_percpu_irq(ppi, arch_timer_handler_phys,
"arch_timer", arch_timer_evt);
if (err)
- free_percpu_irq(arch_timer_ppi[PHYS_SECURE_PPI],
+ free_percpu_irq(arch_timer_ppi[ARCH_TIMER_PHYS_SECURE_PPI],
arch_timer_evt);
}
break;
- case HYP_PPI:
+ case ARCH_TIMER_HYP_PPI:
err = request_percpu_irq(ppi, arch_timer_handler_phys,
"arch_timer", arch_timer_evt);
break;
@@ -737,7 +740,7 @@ static int __init arch_timer_register(void)
out_unreg_notify:
free_percpu_irq(arch_timer_ppi[arch_timer_uses_ppi], arch_timer_evt);
if (arch_timer_has_nonsecure_ppi())
- free_percpu_irq(arch_timer_ppi[PHYS_NONSECURE_PPI],
+ free_percpu_irq(arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI],
arch_timer_evt);
out_free:
@@ -758,7 +761,7 @@ static int __init arch_timer_mem_register(void __iomem *base, unsigned int irq)
t->base = base;
t->evt.irq = irq;
- __arch_timer_setup(ARCH_MEM_TIMER, &t->evt);
+ __arch_timer_setup(ARCH_TIMER_TYPE_MEM, &t->evt);
if (arch_timer_mem_use_virtual)
func = arch_timer_handler_virt_mem;
@@ -801,13 +804,15 @@ arch_timer_needs_probing(int type, const struct of_device_id *matches)
static int __init arch_timer_common_init(void)
{
- unsigned mask = ARCH_CP15_TIMER | ARCH_MEM_TIMER;
+ unsigned mask = ARCH_TIMER_TYPE_CP15 | ARCH_TIMER_TYPE_MEM;
/* Wait until both nodes are probed if we have two timers */
if ((arch_timers_present & mask) != mask) {
- if (arch_timer_needs_probing(ARCH_MEM_TIMER, arch_timer_mem_of_match))
+ if (arch_timer_needs_probing(ARCH_TIMER_TYPE_MEM,
+ arch_timer_mem_of_match))
return 0;
- if (arch_timer_needs_probing(ARCH_CP15_TIMER, arch_timer_of_match))
+ if (arch_timer_needs_probing(ARCH_TIMER_TYPE_CP15,
+ arch_timer_of_match))
return 0;
}
@@ -832,16 +837,16 @@ static int __init arch_timer_init(void)
* their CNTHP_*_EL2 counterparts, and use a different PPI
* number.
*/
- if (is_hyp_mode_available() || !arch_timer_ppi[VIRT_PPI]) {
+ if (is_hyp_mode_available() || !arch_timer_ppi[ARCH_TIMER_VIRT_PPI]) {
bool has_ppi;
if (is_kernel_in_hyp_mode()) {
- arch_timer_uses_ppi = HYP_PPI;
- has_ppi = !!arch_timer_ppi[HYP_PPI];
+ arch_timer_uses_ppi = ARCH_TIMER_HYP_PPI;
+ has_ppi = !!arch_timer_ppi[ARCH_TIMER_HYP_PPI];
} else {
- arch_timer_uses_ppi = PHYS_SECURE_PPI;
- has_ppi = (!!arch_timer_ppi[PHYS_SECURE_PPI] ||
- !!arch_timer_ppi[PHYS_NONSECURE_PPI]);
+ arch_timer_uses_ppi = ARCH_TIMER_PHYS_SECURE_PPI;
+ has_ppi = (!!arch_timer_ppi[ARCH_TIMER_PHYS_SECURE_PPI] ||
+ !!arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI]);
}
if (!has_ppi) {
@@ -858,7 +863,7 @@ static int __init arch_timer_init(void)
if (ret)
return ret;
- arch_timer_kvm_info.virtual_irq = arch_timer_ppi[VIRT_PPI];
+ arch_timer_kvm_info.virtual_irq = arch_timer_ppi[ARCH_TIMER_VIRT_PPI];
return 0;
}
@@ -867,13 +872,13 @@ static int __init arch_timer_of_init(struct device_node *np)
{
int i;
- if (arch_timers_present & ARCH_CP15_TIMER) {
+ if (arch_timers_present & ARCH_TIMER_TYPE_CP15) {
pr_warn("multiple nodes in dt, skipping\n");
return 0;
}
- arch_timers_present |= ARCH_CP15_TIMER;
- for (i = PHYS_SECURE_PPI; i < MAX_TIMER_PPI; i++)
+ arch_timers_present |= ARCH_TIMER_TYPE_CP15;
+ for (i = ARCH_TIMER_PHYS_SECURE_PPI; i < ARCH_TIMER_MAX_TIMER_PPI; i++)
arch_timer_ppi[i] = irq_of_parse_and_map(np, i);
arch_timer_detect_rate(NULL, np);
@@ -895,7 +900,7 @@ static int __init arch_timer_of_init(struct device_node *np)
*/
if (IS_ENABLED(CONFIG_ARM) &&
of_property_read_bool(np, "arm,cpu-registers-not-fw-configured"))
- arch_timer_uses_ppi = PHYS_SECURE_PPI;
+ arch_timer_uses_ppi = ARCH_TIMER_PHYS_SECURE_PPI;
return arch_timer_init();
}
@@ -909,7 +914,7 @@ static int __init arch_timer_mem_init(struct device_node *np)
unsigned int irq, ret = -EINVAL;
u32 cnttidr;
- arch_timers_present |= ARCH_MEM_TIMER;
+ arch_timers_present |= ARCH_TIMER_TYPE_MEM;
cntctlbase = of_iomap(np, 0);
if (!cntctlbase) {
pr_err("Can't find CNTCTLBase\n");
@@ -1008,28 +1013,28 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table)
{
struct acpi_table_gtdt *gtdt;
- if (arch_timers_present & ARCH_CP15_TIMER) {
+ if (arch_timers_present & ARCH_TIMER_TYPE_CP15) {
pr_warn("already initialized, skipping\n");
return -EINVAL;
}
gtdt = container_of(table, struct acpi_table_gtdt, header);
- arch_timers_present |= ARCH_CP15_TIMER;
+ arch_timers_present |= ARCH_TIMER_TYPE_CP15;
- arch_timer_ppi[PHYS_SECURE_PPI] =
+ arch_timer_ppi[ARCH_TIMER_PHYS_SECURE_PPI] =
map_generic_timer_interrupt(gtdt->secure_el1_interrupt,
gtdt->secure_el1_flags);
- arch_timer_ppi[PHYS_NONSECURE_PPI] =
+ arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI] =
map_generic_timer_interrupt(gtdt->non_secure_el1_interrupt,
gtdt->non_secure_el1_flags);
- arch_timer_ppi[VIRT_PPI] =
+ arch_timer_ppi[ARCH_TIMER_VIRT_PPI] =
map_generic_timer_interrupt(gtdt->virtual_timer_interrupt,
gtdt->virtual_timer_flags);
- arch_timer_ppi[HYP_PPI] =
+ arch_timer_ppi[ARCH_TIMER_HYP_PPI] =
map_generic_timer_interrupt(gtdt->non_secure_el2_interrupt,
gtdt->non_secure_el2_flags);
diff --git a/include/clocksource/arm_arch_timer.h b/include/clocksource/arm_arch_timer.h
index d23c381..48376a5 100644
--- a/include/clocksource/arm_arch_timer.h
+++ b/include/clocksource/arm_arch_timer.h
@@ -20,18 +20,18 @@
#include <linux/timecounter.h>
#include <linux/types.h>
-#define ARCH_CP15_TIMER BIT(0)
-#define ARCH_MEM_TIMER BIT(1)
+#define ARCH_TIMER_TYPE_CP15 BIT(0)
+#define ARCH_TIMER_TYPE_MEM BIT(1)
#define ARCH_TIMER_CTRL_ENABLE (1 << 0)
#define ARCH_TIMER_CTRL_IT_MASK (1 << 1)
#define ARCH_TIMER_CTRL_IT_STAT (1 << 2)
-#define CNTHCTL_EL1PCTEN (1 << 0)
-#define CNTHCTL_EL1PCEN (1 << 1)
-#define CNTHCTL_EVNTEN (1 << 2)
-#define CNTHCTL_EVNTDIR (1 << 3)
-#define CNTHCTL_EVNTI (0xF << 4)
+#define ARCH_TIMER_CNTHCTL_EL1PCTEN (1 << 0)
+#define ARCH_TIMER_CNTHCTL_EL1PCEN (1 << 1)
+#define ARCH_TIMER_CNTHCTL_EVNTEN (1 << 2)
+#define ARCH_TIMER_CNTHCTL_EVNTDIR (1 << 3)
+#define ARCH_TIMER_CNTHCTL_EVNTI (0xF << 4)
enum arch_timer_reg {
ARCH_TIMER_REG_CTRL,
@@ -39,11 +39,11 @@ enum arch_timer_reg {
};
enum arch_timer_ppi_nr {
- PHYS_SECURE_PPI,
- PHYS_NONSECURE_PPI,
- VIRT_PPI,
- HYP_PPI,
- MAX_TIMER_PPI
+ ARCH_TIMER_PHYS_SECURE_PPI,
+ ARCH_TIMER_PHYS_NONSECURE_PPI,
+ ARCH_TIMER_VIRT_PPI,
+ ARCH_TIMER_HYP_PPI,
+ ARCH_TIMER_MAX_TIMER_PPI
};
enum arch_timer_spi_nr {
diff --git a/virt/kvm/arm/hyp/timer-sr.c b/virt/kvm/arm/hyp/timer-sr.c
index 798866a..695b9d9 100644
--- a/virt/kvm/arm/hyp/timer-sr.c
+++ b/virt/kvm/arm/hyp/timer-sr.c
@@ -37,7 +37,7 @@ void __hyp_text __timer_save_state(struct kvm_vcpu *vcpu)
/* Allow physical timer/counter access for the host */
val = read_sysreg(cnthctl_el2);
- val |= CNTHCTL_EL1PCTEN | CNTHCTL_EL1PCEN;
+ val |= ARCH_TIMER_CNTHCTL_EL1PCTEN | ARCH_TIMER_CNTHCTL_EL1PCEN;
write_sysreg(val, cnthctl_el2);
/* Clear cntvoff for the host */
@@ -55,8 +55,8 @@ void __hyp_text __timer_restore_state(struct kvm_vcpu *vcpu)
* Physical counter access is allowed
*/
val = read_sysreg(cnthctl_el2);
- val &= ~CNTHCTL_EL1PCEN;
- val |= CNTHCTL_EL1PCTEN;
+ val &= ~ARCH_TIMER_CNTHCTL_EL1PCEN;
+ val |= ARCH_TIMER_CNTHCTL_EL1PCTEN;
write_sysreg(val, cnthctl_el2);
if (timer->enabled) {
--
2.9.3
^ permalink raw reply related
* [PATCH v17 05/15] clocksource/drivers/arm_arch_timer: rework PPI determination
From: fu.wei at linaro.org @ 2016-11-25 8:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161125084623.22515-1-fu.wei@linaro.org>
From: Fu Wei <fu.wei@linaro.org>
Currently, the arch timer driver uses ARCH_TIMER_PHYS_SECURE_PPI to
mean the driver will use the secure PPI *and* potentialy also use the
non-secure PPI. This is somewhat confusing.
For arm64, where it never makes sense to use the secure PPI, this
means we must always request the useless secure PPI, adding to the
confusion. For ACPI, where we may not even have a valid secure PPI
number, this is additionally problematic. We need the driver to be
able to use *only* the non-secure PPI.
The logic to choose which PPI to use is intertwined with other logic
in arch_timer_init(). This patch factors the PPI determination out
into a new function named arch_timer_select_ppi, and then reworks it
so that we can handle having only a non-secure PPI.
This patch also moves arch_timer_ppi verification out to caller,
because we can verify the configuration from device-tree for ARM by this
way.
Meanwhile, because we will select ARCH_TIMER_PHYS_NONSECURE_PPI for ARM64,
the logic in arch_timer_register also need to be updated.
Signed-off-by: Fu Wei <fu.wei@linaro.org>
---
drivers/clocksource/arm_arch_timer.c | 77 +++++++++++++++++++++---------------
1 file changed, 46 insertions(+), 31 deletions(-)
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 231175b..e43be0a 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -699,7 +699,7 @@ static int __init arch_timer_register(void)
case ARCH_TIMER_PHYS_NONSECURE_PPI:
err = request_percpu_irq(ppi, arch_timer_handler_phys,
"arch_timer", arch_timer_evt);
- if (!err && arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI]) {
+ if (!err && arch_timer_has_nonsecure_ppi()) {
ppi = arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI];
err = request_percpu_irq(ppi, arch_timer_handler_phys,
"arch_timer", arch_timer_evt);
@@ -821,39 +821,41 @@ static int __init arch_timer_common_init(void)
return arch_timer_arch_init();
}
-static int __init arch_timer_init(void)
+/**
+ * arch_timer_select_ppi() - Select suitable PPI for the current system.
+ *
+ * If HYP mode is available, we know that the physical timer
+ * has been configured to be accessible from PL1. Use it, so
+ * that a guest can use the virtual timer instead.
+ *
+ * On ARMv8.1 with VH extensions, the kernel runs in HYP. VHE
+ * accesses to CNTP_*_EL1 registers are silently redirected to
+ * their CNTHP_*_EL2 counterparts, and use a different PPI
+ * number.
+ *
+ * If no interrupt provided for virtual timer, we'll have to
+ * stick to the physical timer. It'd better be accessible...
+ * For arm64 we never use the secure interrupt.
+ *
+ * Return: a suitable PPI type for the current system.
+ */
+static enum arch_timer_ppi_nr __init arch_timer_select_ppi(void)
{
- int ret;
- /*
- * If HYP mode is available, we know that the physical timer
- * has been configured to be accessible from PL1. Use it, so
- * that a guest can use the virtual timer instead.
- *
- * If no interrupt provided for virtual timer, we'll have to
- * stick to the physical timer. It'd better be accessible...
- *
- * On ARMv8.1 with VH extensions, the kernel runs in HYP. VHE
- * accesses to CNTP_*_EL1 registers are silently redirected to
- * their CNTHP_*_EL2 counterparts, and use a different PPI
- * number.
- */
- if (is_hyp_mode_available() || !arch_timer_ppi[ARCH_TIMER_VIRT_PPI]) {
- bool has_ppi;
+ if (is_hyp_mode_available() && is_kernel_in_hyp_mode())
+ return ARCH_TIMER_HYP_PPI;
- if (is_kernel_in_hyp_mode()) {
- arch_timer_uses_ppi = ARCH_TIMER_HYP_PPI;
- has_ppi = !!arch_timer_ppi[ARCH_TIMER_HYP_PPI];
- } else {
- arch_timer_uses_ppi = ARCH_TIMER_PHYS_SECURE_PPI;
- has_ppi = (!!arch_timer_ppi[ARCH_TIMER_PHYS_SECURE_PPI] ||
- !!arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI]);
- }
+ if (arch_timer_ppi[ARCH_TIMER_VIRT_PPI])
+ return ARCH_TIMER_VIRT_PPI;
- if (!has_ppi) {
- pr_warn("No interrupt available, giving up\n");
- return -EINVAL;
- }
- }
+ if (IS_ENABLED(CONFIG_ARM64))
+ return ARCH_TIMER_PHYS_NONSECURE_PPI;
+
+ return ARCH_TIMER_PHYS_SECURE_PPI;
+}
+
+static int __init arch_timer_init(void)
+{
+ int ret;
ret = arch_timer_register();
if (ret)
@@ -901,6 +903,13 @@ static int __init arch_timer_of_init(struct device_node *np)
if (IS_ENABLED(CONFIG_ARM) &&
of_property_read_bool(np, "arm,cpu-registers-not-fw-configured"))
arch_timer_uses_ppi = ARCH_TIMER_PHYS_SECURE_PPI;
+ else
+ arch_timer_uses_ppi = arch_timer_select_ppi();
+
+ if (!arch_timer_ppi[arch_timer_uses_ppi]) {
+ pr_err("No interrupt available, giving up\n");
+ return -EINVAL;
+ }
return arch_timer_init();
}
@@ -1041,6 +1050,12 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table)
/* Get the frequency from CNTFRQ */
arch_timer_detect_rate(NULL, NULL);
+ arch_timer_uses_ppi = arch_timer_select_ppi();
+ if (!arch_timer_ppi[arch_timer_uses_ppi]) {
+ pr_err("No interrupt available, giving up\n");
+ return -EINVAL;
+ }
+
/* Always-on capability */
arch_timer_c3stop = !(gtdt->non_secure_el1_flags & ACPI_GTDT_ALWAYS_ON);
--
2.9.3
^ permalink raw reply related
* [PATCH v17 06/15] clocksource/drivers/arm_arch_timer: Rework counter frequency detection.
From: fu.wei at linaro.org @ 2016-11-25 8:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161125084623.22515-1-fu.wei@linaro.org>
From: Fu Wei <fu.wei@linaro.org>
Currently, the counter frequency detection call(arch_timer_detect_rate)
combines all the ways to get counter frequency: device-tree property,
system coprocessor register, MMIO timer. But in the most of use cases,
we don't need all the ways to try:
For example, reading device-tree property will be needed only when
system boot with device-tree, getting frequency from MMIO timer register
will beneeded only when we init MMIO timer.
This patch separates paths to determine frequency:
Separate out device-tree code, keep them in device-tree init function.
Separate out the MMIO frequency and the sysreg frequency detection call,
and use the appropriate one for the counter.
Signed-off-by: Fu Wei <fu.wei@linaro.org>
---
drivers/clocksource/arm_arch_timer.c | 49 +++++++++++++++++++++++-------------
1 file changed, 31 insertions(+), 18 deletions(-)
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index e43be0a..e554081 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -487,27 +487,31 @@ static int arch_timer_starting_cpu(unsigned int cpu)
return 0;
}
-static void
-arch_timer_detect_rate(void __iomem *cntbase, struct device_node *np)
+static void arch_timer_detect_rate(void)
{
- /* Who has more than one independent system counter? */
- if (arch_timer_rate)
- return;
+ /*
+ * Try to get the timer frequency from
+ * cntfrq_el0(system coprocessor register).
+ */
+ if (!arch_timer_rate)
+ arch_timer_rate = arch_timer_get_cntfrq();
+
+ /* Check the timer frequency. */
+ if (!arch_timer_rate)
+ pr_warn("frequency not available\n");
+}
+static void arch_timer_mem_detect_rate(void __iomem *cntbase)
+{
/*
- * Try to determine the frequency from the device tree or CNTFRQ,
- * if ACPI is enabled, get the frequency from CNTFRQ ONLY.
+ * Try to determine the frequency from
+ * CNTFRQ in memory-mapped timer.
*/
- if (!acpi_disabled ||
- of_property_read_u32(np, "clock-frequency", &arch_timer_rate)) {
- if (cntbase)
- arch_timer_rate = readl_relaxed(cntbase + CNTFRQ);
- else
- arch_timer_rate = arch_timer_get_cntfrq();
- }
+ if (!arch_timer_rate)
+ arch_timer_rate = readl_relaxed(cntbase + CNTFRQ);
/* Check the timer frequency. */
- if (arch_timer_rate == 0)
+ if (!arch_timer_rate)
pr_warn("frequency not available\n");
}
@@ -883,7 +887,9 @@ static int __init arch_timer_of_init(struct device_node *np)
for (i = ARCH_TIMER_PHYS_SECURE_PPI; i < ARCH_TIMER_MAX_TIMER_PPI; i++)
arch_timer_ppi[i] = irq_of_parse_and_map(np, i);
- arch_timer_detect_rate(NULL, np);
+ if (!arch_timer_rate &&
+ of_property_read_u32(np, "clock-frequency", &arch_timer_rate))
+ arch_timer_detect_rate();
arch_timer_c3stop = !of_property_read_bool(np, "always-on");
@@ -986,7 +992,14 @@ static int __init arch_timer_mem_init(struct device_node *np)
goto out;
}
- arch_timer_detect_rate(base, np);
+ /*
+ * Try to determine the frequency from the device tree,
+ * if fail, get the frequency from CNTFRQ.
+ */
+ if (!arch_timer_rate &&
+ of_property_read_u32(np, "clock-frequency", &arch_timer_rate))
+ arch_timer_mem_detect_rate(base);
+
ret = arch_timer_mem_register(base, irq);
if (ret)
goto out;
@@ -1048,7 +1061,7 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table)
gtdt->non_secure_el2_flags);
/* Get the frequency from CNTFRQ */
- arch_timer_detect_rate(NULL, NULL);
+ arch_timer_detect_rate();
arch_timer_uses_ppi = arch_timer_select_ppi();
if (!arch_timer_ppi[arch_timer_uses_ppi]) {
--
2.9.3
^ permalink raw reply related
* [PATCH v17 07/15] clocksource/drivers/arm_arch_timer: Refactor arch_timer_needs_probing
From: fu.wei at linaro.org @ 2016-11-25 8:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161125084623.22515-1-fu.wei@linaro.org>
From: Fu Wei <fu.wei@linaro.org>
When system init with device-tree, we don't know which node will be
initialized first. And the code in arch_timer_common_init should wait
until per-cpu timer and MMIO timer are both initialized. So we need
arch_timer_needs_probing to detect the init status of system.
But currently the code is dispersed in arch_timer_needs_probing and
arch_timer_common_init. And the function name doesn't specify that
it's only for device-tree. This is somewhat confusing.
This patch move all related code from arch_timer_common_init to
arch_timer_needs_probing, refactor it, and rename it to
arch_timer_needs_of_probing. And make sure that it will be called
only if acpi is disabled.
Signed-off-by: Fu Wei <fu.wei@linaro.org>
---
drivers/clocksource/arm_arch_timer.c | 34 +++++++++++++++++++---------------
1 file changed, 19 insertions(+), 15 deletions(-)
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index e554081..2c9085a 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -792,15 +792,28 @@ static const struct of_device_id arch_timer_mem_of_match[] __initconst = {
{},
};
-static bool __init
-arch_timer_needs_probing(int type, const struct of_device_id *matches)
+static bool __init arch_timer_needs_of_probing(void)
{
struct device_node *dn;
bool needs_probing = false;
+ unsigned int mask = ARCH_TIMER_TYPE_CP15 | ARCH_TIMER_TYPE_MEM;
- dn = of_find_matching_node(NULL, matches);
- if (dn && of_device_is_available(dn) && !(arch_timers_present & type))
+ /* We have two timers, and both device-tree nodes are probed. */
+ if ((arch_timers_present & mask) == mask)
+ return false;
+
+ /*
+ * Only one type of timer is probed,
+ * check if we have another type of timer node in device-tree.
+ */
+ if (arch_timers_present & ARCH_TIMER_TYPE_CP15)
+ dn = of_find_matching_node(NULL, arch_timer_mem_of_match);
+ else
+ dn = of_find_matching_node(NULL, arch_timer_of_match);
+
+ if (dn && of_device_is_available(dn))
needs_probing = true;
+
of_node_put(dn);
return needs_probing;
@@ -808,17 +821,8 @@ arch_timer_needs_probing(int type, const struct of_device_id *matches)
static int __init arch_timer_common_init(void)
{
- unsigned mask = ARCH_TIMER_TYPE_CP15 | ARCH_TIMER_TYPE_MEM;
-
- /* Wait until both nodes are probed if we have two timers */
- if ((arch_timers_present & mask) != mask) {
- if (arch_timer_needs_probing(ARCH_TIMER_TYPE_MEM,
- arch_timer_mem_of_match))
- return 0;
- if (arch_timer_needs_probing(ARCH_TIMER_TYPE_CP15,
- arch_timer_of_match))
- return 0;
- }
+ if (acpi_disabled && arch_timer_needs_of_probing())
+ return 0;
arch_timer_banner(arch_timers_present);
arch_counter_register(arch_timers_present);
--
2.9.3
^ permalink raw reply related
* [PATCH v17 08/15] clocksource/drivers/arm_arch_timer: move arch_timer_needs_of_probing into DT init call
From: fu.wei at linaro.org @ 2016-11-25 8:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161125084623.22515-1-fu.wei@linaro.org>
From: Fu Wei <fu.wei@linaro.org>
Because arch_timer_needs_of_probing is only for booting with device-tree,
but arch_timer_common_init is a generic init call which shouldn't include
the FW-specific code. It's better to put arch_timer_needs_of_probing into
DT init function.
But for per-cpu timer, the arch_timer_common_init is called from
arch_timer_init. For reaching the goal above, this patch disassemble
arch_timer_init and use arch_timer_register and arch_timer_common_init
directly, just like arch_timer_mem init code is doing.
By this way, all the DT relevant code are only called from DT init call.
Signed-off-by: Fu Wei <fu.wei@linaro.org>
---
drivers/clocksource/arm_arch_timer.c | 45 ++++++++++++++++--------------------
1 file changed, 20 insertions(+), 25 deletions(-)
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 2c9085a..4549008 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -821,9 +821,6 @@ static bool __init arch_timer_needs_of_probing(void)
static int __init arch_timer_common_init(void)
{
- if (acpi_disabled && arch_timer_needs_of_probing())
- return 0;
-
arch_timer_banner(arch_timers_present);
arch_counter_register(arch_timers_present);
return arch_timer_arch_init();
@@ -861,26 +858,9 @@ static enum arch_timer_ppi_nr __init arch_timer_select_ppi(void)
return ARCH_TIMER_PHYS_SECURE_PPI;
}
-static int __init arch_timer_init(void)
-{
- int ret;
-
- ret = arch_timer_register();
- if (ret)
- return ret;
-
- ret = arch_timer_common_init();
- if (ret)
- return ret;
-
- arch_timer_kvm_info.virtual_irq = arch_timer_ppi[ARCH_TIMER_VIRT_PPI];
-
- return 0;
-}
-
static int __init arch_timer_of_init(struct device_node *np)
{
- int i;
+ int i, ret;
if (arch_timers_present & ARCH_TIMER_TYPE_CP15) {
pr_warn("multiple nodes in dt, skipping\n");
@@ -891,6 +871,8 @@ static int __init arch_timer_of_init(struct device_node *np)
for (i = ARCH_TIMER_PHYS_SECURE_PPI; i < ARCH_TIMER_MAX_TIMER_PPI; i++)
arch_timer_ppi[i] = irq_of_parse_and_map(np, i);
+ arch_timer_kvm_info.virtual_irq = arch_timer_ppi[ARCH_TIMER_VIRT_PPI];
+
if (!arch_timer_rate &&
of_property_read_u32(np, "clock-frequency", &arch_timer_rate))
arch_timer_detect_rate();
@@ -921,7 +903,14 @@ static int __init arch_timer_of_init(struct device_node *np)
return -EINVAL;
}
- return arch_timer_init();
+ ret = arch_timer_register();
+ if (ret)
+ return ret;
+
+ if (arch_timer_needs_of_probing())
+ return 0;
+
+ return arch_timer_common_init();
}
CLOCKSOURCE_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer", arch_timer_of_init);
CLOCKSOURCE_OF_DECLARE(armv8_arch_timer, "arm,armv8-timer", arch_timer_of_init);
@@ -1008,7 +997,8 @@ static int __init arch_timer_mem_init(struct device_node *np)
if (ret)
goto out;
- return arch_timer_common_init();
+ if (!arch_timer_needs_of_probing())
+ ret = arch_timer_common_init();
out:
iounmap(cntctlbase);
of_node_put(best_frame);
@@ -1064,6 +1054,8 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table)
map_generic_timer_interrupt(gtdt->non_secure_el2_interrupt,
gtdt->non_secure_el2_flags);
+ arch_timer_kvm_info.virtual_irq = arch_timer_ppi[ARCH_TIMER_VIRT_PPI];
+
/* Get the frequency from CNTFRQ */
arch_timer_detect_rate();
@@ -1076,8 +1068,11 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table)
/* Always-on capability */
arch_timer_c3stop = !(gtdt->non_secure_el1_flags & ACPI_GTDT_ALWAYS_ON);
- arch_timer_init();
- return 0;
+ ret = arch_timer_register();
+ if (ret)
+ return ret;
+
+ return arch_timer_common_init();
}
CLOCKSOURCE_ACPI_DECLARE(arch_timer, ACPI_SIG_GTDT, arch_timer_acpi_init);
#endif
--
2.9.3
^ permalink raw reply related
* [PATCH v17 09/15] clocksource/drivers/arm_arch_timer: Introduce some new structs to prepare for GTDT
From: fu.wei at linaro.org @ 2016-11-25 8:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161125084623.22515-1-fu.wei@linaro.org>
From: Fu Wei <fu.wei@linaro.org>
The patch introduce two new structs: arch_timer_mem, arch_timer_mem_frame.
And also introduce a new define: ARCH_TIMER_MEM_MAX_FRAMES
These will be used for refactoring the memory-mapped timer init code to
prepare for GTDT
Signed-off-by: Fu Wei <fu.wei@linaro.org>
---
include/clocksource/arm_arch_timer.h | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/include/clocksource/arm_arch_timer.h b/include/clocksource/arm_arch_timer.h
index 48376a5..3403247 100644
--- a/include/clocksource/arm_arch_timer.h
+++ b/include/clocksource/arm_arch_timer.h
@@ -57,6 +57,8 @@ enum arch_timer_spi_nr {
#define ARCH_TIMER_MEM_PHYS_ACCESS 2
#define ARCH_TIMER_MEM_VIRT_ACCESS 3
+#define ARCH_TIMER_MEM_MAX_FRAMES 8
+
#define ARCH_TIMER_USR_PCT_ACCESS_EN (1 << 0) /* physical counter */
#define ARCH_TIMER_USR_VCT_ACCESS_EN (1 << 1) /* virtual counter */
#define ARCH_TIMER_VIRT_EVT_EN (1 << 2)
@@ -72,6 +74,21 @@ struct arch_timer_kvm_info {
int virtual_irq;
};
+struct arch_timer_mem_frame {
+ int frame_nr;
+ phys_addr_t cntbase;
+ size_t size;
+ int phys_irq;
+ int virt_irq;
+};
+
+struct arch_timer_mem {
+ phys_addr_t cntctlbase;
+ size_t size;
+ int num_frames;
+ struct arch_timer_mem_frame frame[ARCH_TIMER_MEM_MAX_FRAMES];
+};
+
#ifdef CONFIG_ARM_ARCH_TIMER
extern u32 arch_timer_get_rate(void);
--
2.9.3
^ permalink raw reply related
* [PATCH v17 10/15] clocksource/drivers/arm_arch_timer: Refactor the timer init code to prepare for GTDT
From: fu.wei at linaro.org @ 2016-11-25 8:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161125084623.22515-1-fu.wei@linaro.org>
From: Fu Wei <fu.wei@linaro.org>
The patch refactor original memory-mapped timer init code:
(1) Refactor "arch_timer_mem_init", make it become a common code for
memory-mapped timer init.
(2) Add a new function "arch_timer_mem_of_init" for DT init.
Signed-off-by: Fu Wei <fu.wei@linaro.org>
---
drivers/clocksource/arm_arch_timer.c | 130 ++++++++++++++++++++++++-----------
1 file changed, 88 insertions(+), 42 deletions(-)
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 4549008..bcdceca 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -915,17 +915,17 @@ static int __init arch_timer_of_init(struct device_node *np)
CLOCKSOURCE_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer", arch_timer_of_init);
CLOCKSOURCE_OF_DECLARE(armv8_arch_timer, "arm,armv8-timer", arch_timer_of_init);
-static int __init arch_timer_mem_init(struct device_node *np)
+static int __init arch_timer_mem_init(struct arch_timer_mem *timer_mem)
{
- struct device_node *frame, *best_frame = NULL;
void __iomem *cntctlbase, *base;
- unsigned int irq, ret = -EINVAL;
+ struct arch_timer_mem_frame *best_frame = NULL;
+ unsigned int irq;
u32 cnttidr;
+ int i, ret;
- arch_timers_present |= ARCH_TIMER_TYPE_MEM;
- cntctlbase = of_iomap(np, 0);
+ cntctlbase = ioremap(timer_mem->cntctlbase, timer_mem->size);
if (!cntctlbase) {
- pr_err("Can't find CNTCTLBase\n");
+ pr_err("Can't map CNTCTLBase.\n");
return -ENXIO;
}
@@ -935,26 +935,18 @@ static int __init arch_timer_mem_init(struct device_node *np)
* Try to find a virtual capable frame. Otherwise fall back to a
* physical capable frame.
*/
- for_each_available_child_of_node(np, frame) {
- int n;
- u32 cntacr;
-
- if (of_property_read_u32(frame, "frame-number", &n)) {
- pr_err("Missing frame-number\n");
- of_node_put(frame);
- goto out;
- }
+ for (i = 0; i < timer_mem->num_frames; i++) {
+ u32 cntacr = CNTACR_RFRQ | CNTACR_RWPT | CNTACR_RPCT |
+ CNTACR_RWVT | CNTACR_RVOFF | CNTACR_RVCT;
+ int n = timer_mem->frame[i].frame_nr;
/* Try enabling everything, and see what sticks */
- cntacr = CNTACR_RFRQ | CNTACR_RWPT | CNTACR_RPCT |
- CNTACR_RWVT | CNTACR_RVOFF | CNTACR_RVCT;
writel_relaxed(cntacr, cntctlbase + CNTACR(n));
cntacr = readl_relaxed(cntctlbase + CNTACR(n));
if ((cnttidr & CNTTIDR_VIRT(n)) &&
!(~cntacr & (CNTACR_RWVT | CNTACR_RVCT))) {
- of_node_put(best_frame);
- best_frame = frame;
+ best_frame = &timer_mem->frame[i];
arch_timer_mem_use_virtual = true;
break;
}
@@ -962,50 +954,104 @@ static int __init arch_timer_mem_init(struct device_node *np)
if (~cntacr & (CNTACR_RWPT | CNTACR_RPCT))
continue;
- of_node_put(best_frame);
- best_frame = of_node_get(frame);
+ best_frame = &timer_mem->frame[i];
}
+ iounmap(cntctlbase);
- ret= -ENXIO;
- base = arch_counter_base = of_iomap(best_frame, 0);
- if (!base) {
- pr_err("Can't map frame's registers\n");
- goto out;
+ if (!best_frame) {
+ pr_err("Can't find frame for register\n");
+ return -EINVAL;
}
if (arch_timer_mem_use_virtual)
- irq = irq_of_parse_and_map(best_frame, ARCH_TIMER_VIRT_SPI);
+ irq = best_frame->virt_irq;
else
- irq = irq_of_parse_and_map(best_frame, ARCH_TIMER_PHYS_SPI);
+ irq = best_frame->phys_irq;
- ret = -EINVAL;
if (!irq) {
pr_err("Frame missing %s irq",
arch_timer_mem_use_virtual ? "virt" : "phys");
- goto out;
+ return -EINVAL;
}
- /*
- * Try to determine the frequency from the device tree,
- * if fail, get the frequency from CNTFRQ.
- */
- if (!arch_timer_rate &&
- of_property_read_u32(np, "clock-frequency", &arch_timer_rate))
- arch_timer_mem_detect_rate(base);
+ base = ioremap(best_frame->cntbase, best_frame->size);
+ if (!base) {
+ pr_err("Can't map frame's registers\n");
+ return -ENXIO;
+ }
+
+ arch_timer_mem_detect_rate(base);
ret = arch_timer_mem_register(base, irq);
- if (ret)
+ if (ret) {
+ iounmap(base);
+ return ret;
+ }
+
+ arch_counter_base = base;
+ arch_timers_present |= ARCH_TIMER_TYPE_MEM;
+
+ return 0;
+}
+
+static int __init arch_timer_mem_of_init(struct device_node *np)
+{
+ struct arch_timer_mem *timer_mem;
+ struct device_node *frame_node;
+ struct resource res;
+ int i, ret = -EINVAL;
+
+ timer_mem = kzalloc(sizeof(*timer_mem), GFP_KERNEL);
+ if (!timer_mem)
+ return -ENOMEM;
+
+ if (of_address_to_resource(np, 0, &res))
goto out;
+ timer_mem->cntctlbase = res.start;
+ timer_mem->size = resource_size(&res);
+
+ i = 0;
+ for_each_available_child_of_node(np, frame_node) {
+ int n;
+ struct arch_timer_mem_frame *frame = &timer_mem->frame[i];
+
+ if (of_property_read_u32(frame_node, "frame-number", &n)) {
+ pr_err("Missing frame-number\n");
+ of_node_put(frame_node);
+ goto out;
+ }
+ frame->frame_nr = n;
+
+ if (of_address_to_resource(frame_node, 0, &res)) {
+ of_node_put(frame_node);
+ goto out;
+ }
+ frame->cntbase = res.start;
+ frame->size = resource_size(&res);
+
+ frame->virt_irq = irq_of_parse_and_map(frame_node,
+ ARCH_TIMER_VIRT_SPI);
+ frame->phys_irq = irq_of_parse_and_map(frame_node,
+ ARCH_TIMER_PHYS_SPI);
- if (!arch_timer_needs_of_probing())
+ if (++i >= ARCH_TIMER_MEM_MAX_FRAMES)
+ break;
+ }
+ timer_mem->num_frames = i;
+
+ /* Try to determine the frequency from the device tree */
+ if (!arch_timer_rate)
+ of_property_read_u32(np, "clock-frequency", &arch_timer_rate);
+
+ ret = arch_timer_mem_init(timer_mem);
+ if (!ret && !arch_timer_needs_of_probing())
ret = arch_timer_common_init();
out:
- iounmap(cntctlbase);
- of_node_put(best_frame);
+ kfree(timer_mem);
return ret;
}
CLOCKSOURCE_OF_DECLARE(armv7_arch_timer_mem, "arm,armv7-timer-mem",
- arch_timer_mem_init);
+ arch_timer_mem_of_init);
#ifdef CONFIG_ACPI
static int __init map_generic_timer_interrupt(u32 interrupt, u32 flags)
--
2.9.3
^ permalink raw reply related
* [PATCH v17 11/15] acpi/arm64: Add GTDT table parse driver
From: fu.wei at linaro.org @ 2016-11-25 8:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161125084623.22515-1-fu.wei@linaro.org>
From: Fu Wei <fu.wei@linaro.org>
This patch adds support for parsing arch timer info in GTDT,
provides some kernel APIs to parse all the PPIs and
always-on info in GTDT and export them.
By this driver, we can simplify arm_arch_timer drivers, and
separate the ACPI GTDT knowledge from it.
Signed-off-by: Fu Wei <fu.wei@linaro.org>
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
arch/arm64/Kconfig | 1 +
drivers/acpi/arm64/Kconfig | 3 +
drivers/acpi/arm64/Makefile | 1 +
drivers/acpi/arm64/gtdt.c | 157 ++++++++++++++++++++++++++++++++++++++++++++
include/linux/acpi.h | 6 ++
5 files changed, 168 insertions(+)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 969ef88..4277a21 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -2,6 +2,7 @@ config ARM64
def_bool y
select ACPI_CCA_REQUIRED if ACPI
select ACPI_GENERIC_GSI if ACPI
+ select ACPI_GTDT if ACPI
select ACPI_REDUCED_HARDWARE_ONLY if ACPI
select ACPI_MCFG if ACPI
select ACPI_SPCR_TABLE if ACPI
diff --git a/drivers/acpi/arm64/Kconfig b/drivers/acpi/arm64/Kconfig
index 4616da4..5a6f80f 100644
--- a/drivers/acpi/arm64/Kconfig
+++ b/drivers/acpi/arm64/Kconfig
@@ -4,3 +4,6 @@
config ACPI_IORT
bool
+
+config ACPI_GTDT
+ bool
diff --git a/drivers/acpi/arm64/Makefile b/drivers/acpi/arm64/Makefile
index 72331f2..1017def 100644
--- a/drivers/acpi/arm64/Makefile
+++ b/drivers/acpi/arm64/Makefile
@@ -1 +1,2 @@
obj-$(CONFIG_ACPI_IORT) += iort.o
+obj-$(CONFIG_ACPI_GTDT) += gtdt.o
diff --git a/drivers/acpi/arm64/gtdt.c b/drivers/acpi/arm64/gtdt.c
new file mode 100644
index 0000000..d93a790
--- /dev/null
+++ b/drivers/acpi/arm64/gtdt.c
@@ -0,0 +1,157 @@
+/*
+ * ARM Specific GTDT table Support
+ *
+ * Copyright (C) 2016, Linaro Ltd.
+ * Author: Daniel Lezcano <daniel.lezcano@linaro.org>
+ * Fu Wei <fu.wei@linaro.org>
+ * Hanjun Guo <hanjun.guo@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/acpi.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+
+#include <clocksource/arm_arch_timer.h>
+
+#undef pr_fmt
+#define pr_fmt(fmt) "ACPI GTDT: " fmt
+
+/**
+ * struct acpi_gtdt_descriptor - Store the key info of GTDT for all functions
+ * @gtdt: The pointer to the struct acpi_table_gtdt of GTDT table.
+ * @gtdt_end: The pointer to the end of GTDT table.
+ * @platform_timer: The pointer to the start of Platform Timer Structure
+ *
+ * The struct store the key info of GTDT table, it should be initialized by
+ * acpi_gtdt_init.
+ */
+struct acpi_gtdt_descriptor {
+ struct acpi_table_gtdt *gtdt;
+ void *gtdt_end;
+ void *platform_timer;
+};
+
+static struct acpi_gtdt_descriptor acpi_gtdt_desc __initdata;
+
+static int __init map_gt_gsi(u32 interrupt, u32 flags)
+{
+ int trigger, polarity;
+
+ trigger = (flags & ACPI_GTDT_INTERRUPT_MODE) ? ACPI_EDGE_SENSITIVE
+ : ACPI_LEVEL_SENSITIVE;
+
+ polarity = (flags & ACPI_GTDT_INTERRUPT_POLARITY) ? ACPI_ACTIVE_LOW
+ : ACPI_ACTIVE_HIGH;
+
+ return acpi_register_gsi(NULL, interrupt, trigger, polarity);
+}
+
+/**
+ * acpi_gtdt_map_ppi() - Map the PPIs of per-cpu arch_timer.
+ * @type: the type of PPI.
+ *
+ * Note: Linux on arm64 isn't supported on the secure side.
+ * So we only handle the non-secure timer PPIs,
+ * ARCH_TIMER_PHYS_SECURE_PPI is treated as invalid type.
+ *
+ * Return: the mapped PPI value, 0 if error.
+ */
+int __init acpi_gtdt_map_ppi(int type)
+{
+ struct acpi_table_gtdt *gtdt = acpi_gtdt_desc.gtdt;
+
+ switch (type) {
+ case ARCH_TIMER_PHYS_NONSECURE_PPI:
+ return map_gt_gsi(gtdt->non_secure_el1_interrupt,
+ gtdt->non_secure_el1_flags);
+ case ARCH_TIMER_VIRT_PPI:
+ return map_gt_gsi(gtdt->virtual_timer_interrupt,
+ gtdt->virtual_timer_flags);
+
+ case ARCH_TIMER_HYP_PPI:
+ return map_gt_gsi(gtdt->non_secure_el2_interrupt,
+ gtdt->non_secure_el2_flags);
+ default:
+ pr_err("Failed to map timer interrupt: invalid type.\n");
+ }
+
+ return 0;
+}
+
+/**
+ * acpi_gtdt_c3stop() - Got c3stop info from GTDT according to the type of PPI.
+ * @type: the type of PPI.
+ *
+ * Return: 1 if the timer can be in deep idle state, 0 otherwise.
+ */
+bool __init acpi_gtdt_c3stop(int type)
+{
+ struct acpi_table_gtdt *gtdt = acpi_gtdt_desc.gtdt;
+
+ switch (type) {
+ case ARCH_TIMER_PHYS_NONSECURE_PPI:
+ return !(gtdt->non_secure_el1_flags & ACPI_GTDT_ALWAYS_ON);
+
+ case ARCH_TIMER_VIRT_PPI:
+ return !(gtdt->virtual_timer_flags & ACPI_GTDT_ALWAYS_ON);
+
+ case ARCH_TIMER_HYP_PPI:
+ return !(gtdt->non_secure_el2_flags & ACPI_GTDT_ALWAYS_ON);
+
+ default:
+ pr_err("Failed to get c3stop info: invalid type.\n");
+ }
+
+ return 0;
+}
+
+/**
+ * acpi_gtdt_init() - Get the info of GTDT table to prepare for further init.
+ * @table: The pointer to GTDT table.
+ * @platform_timer_count: The pointer of int variate for returning the
+ * number of platform timers. It can be NULL, if
+ * driver don't need this info.
+ *
+ * Return: 0 if success, -EINVAL if error.
+ */
+int __init acpi_gtdt_init(struct acpi_table_header *table,
+ int *platform_timer_count)
+{
+ int ret = 0;
+ int timer_count = 0;
+ void *platform_timer = NULL;
+ struct acpi_table_gtdt *gtdt;
+
+ gtdt = container_of(table, struct acpi_table_gtdt, header);
+ acpi_gtdt_desc.gtdt = gtdt;
+ acpi_gtdt_desc.gtdt_end = (void *)table + table->length;
+
+ if (table->revision < 2)
+ pr_debug("Revision:%d doesn't support Platform Timers.\n",
+ table->revision);
+ else if (!gtdt->platform_timer_count)
+ pr_debug("No Platform Timer.\n");
+ else
+ timer_count = gtdt->platform_timer_count;
+
+ if (timer_count) {
+ platform_timer = (void *)gtdt + gtdt->platform_timer_offset;
+ if (platform_timer < (void *)table +
+ sizeof(struct acpi_table_gtdt)) {
+ pr_err(FW_BUG "invalid timer data.\n");
+ timer_count = 0;
+ platform_timer = NULL;
+ ret = -EINVAL;
+ }
+ }
+
+ acpi_gtdt_desc.platform_timer = platform_timer;
+ if (platform_timer_count)
+ *platform_timer_count = timer_count;
+
+ return ret;
+}
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 61a3d90..d201ce4 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -577,6 +577,12 @@ enum acpi_reconfig_event {
int acpi_reconfig_notifier_register(struct notifier_block *nb);
int acpi_reconfig_notifier_unregister(struct notifier_block *nb);
+#ifdef CONFIG_ACPI_GTDT
+int acpi_gtdt_init(struct acpi_table_header *table, int *platform_timer_count);
+int acpi_gtdt_map_ppi(int type);
+bool acpi_gtdt_c3stop(int type);
+#endif
+
#else /* !CONFIG_ACPI */
#define acpi_disabled 1
--
2.9.3
^ permalink raw reply related
* [PATCH v17 12/15] clocksource/drivers/arm_arch_timer: Simplify ACPI support code.
From: fu.wei at linaro.org @ 2016-11-25 8:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161125084623.22515-1-fu.wei@linaro.org>
From: Fu Wei <fu.wei@linaro.org>
The patch update arm_arch_timer driver to use the function
provided by the new GTDT driver of ACPI.
By this way, arm_arch_timer.c can be simplified, and separate
all the ACPI GTDT knowledge from this timer driver.
Signed-off-by: Fu Wei <fu.wei@linaro.org>
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
Tested-by: Xiongfeng Wang <wangxiongfeng2@huawei.com>
---
drivers/clocksource/arm_arch_timer.c | 47 +++++++++++-------------------------
1 file changed, 14 insertions(+), 33 deletions(-)
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index bcdceca..7f059f9 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -1053,58 +1053,36 @@ static int __init arch_timer_mem_of_init(struct device_node *np)
CLOCKSOURCE_OF_DECLARE(armv7_arch_timer_mem, "arm,armv7-timer-mem",
arch_timer_mem_of_init);
-#ifdef CONFIG_ACPI
-static int __init map_generic_timer_interrupt(u32 interrupt, u32 flags)
-{
- int trigger, polarity;
-
- if (!interrupt)
- return 0;
-
- trigger = (flags & ACPI_GTDT_INTERRUPT_MODE) ? ACPI_EDGE_SENSITIVE
- : ACPI_LEVEL_SENSITIVE;
-
- polarity = (flags & ACPI_GTDT_INTERRUPT_POLARITY) ? ACPI_ACTIVE_LOW
- : ACPI_ACTIVE_HIGH;
-
- return acpi_register_gsi(NULL, interrupt, trigger, polarity);
-}
-
+#ifdef CONFIG_ACPI_GTDT
/* Initialize per-processor generic timer */
static int __init arch_timer_acpi_init(struct acpi_table_header *table)
{
- struct acpi_table_gtdt *gtdt;
+ int ret;
if (arch_timers_present & ARCH_TIMER_TYPE_CP15) {
pr_warn("already initialized, skipping\n");
return -EINVAL;
}
- gtdt = container_of(table, struct acpi_table_gtdt, header);
-
arch_timers_present |= ARCH_TIMER_TYPE_CP15;
- arch_timer_ppi[ARCH_TIMER_PHYS_SECURE_PPI] =
- map_generic_timer_interrupt(gtdt->secure_el1_interrupt,
- gtdt->secure_el1_flags);
+ ret = acpi_gtdt_init(table, NULL);
+ if (ret) {
+ pr_err("Failed to init GTDT table.\n");
+ return ret;
+ }
arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI] =
- map_generic_timer_interrupt(gtdt->non_secure_el1_interrupt,
- gtdt->non_secure_el1_flags);
+ acpi_gtdt_map_ppi(ARCH_TIMER_PHYS_NONSECURE_PPI);
arch_timer_ppi[ARCH_TIMER_VIRT_PPI] =
- map_generic_timer_interrupt(gtdt->virtual_timer_interrupt,
- gtdt->virtual_timer_flags);
+ acpi_gtdt_map_ppi(ARCH_TIMER_VIRT_PPI);
arch_timer_ppi[ARCH_TIMER_HYP_PPI] =
- map_generic_timer_interrupt(gtdt->non_secure_el2_interrupt,
- gtdt->non_secure_el2_flags);
+ acpi_gtdt_map_ppi(ARCH_TIMER_HYP_PPI);
arch_timer_kvm_info.virtual_irq = arch_timer_ppi[ARCH_TIMER_VIRT_PPI];
- /* Get the frequency from CNTFRQ */
- arch_timer_detect_rate();
-
arch_timer_uses_ppi = arch_timer_select_ppi();
if (!arch_timer_ppi[arch_timer_uses_ppi]) {
pr_err("No interrupt available, giving up\n");
@@ -1112,7 +1090,10 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table)
}
/* Always-on capability */
- arch_timer_c3stop = !(gtdt->non_secure_el1_flags & ACPI_GTDT_ALWAYS_ON);
+ arch_timer_c3stop = acpi_gtdt_c3stop(arch_timer_uses_ppi);
+
+ /* Get the frequency from CNTFRQ */
+ arch_timer_detect_rate();
ret = arch_timer_register();
if (ret)
--
2.9.3
^ permalink raw reply related
* [PATCH v17 13/15] acpi/arm64: Add memory-mapped timer support in GTDT driver
From: fu.wei at linaro.org @ 2016-11-25 8:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161125084623.22515-1-fu.wei@linaro.org>
From: Fu Wei <fu.wei@linaro.org>
On platforms booting with ACPI, architected memory-mapped timers'
configuration data is provided by firmware through the ACPI GTDT
static table.
The clocksource architected timer kernel driver requires a firmware
interface to collect timer configuration and configure its driver.
this infrastructure is present for device tree systems, but it is
missing on systems booting with ACPI.
Implement the kernel infrastructure required to parse the static
ACPI GTDT table so that the architected timer clocksource driver can
make use of it on systems booting with ACPI, therefore enabling
the corresponding timers configuration.
Signed-off-by: Fu Wei <fu.wei@linaro.org>
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
---
drivers/acpi/arm64/gtdt.c | 124 ++++++++++++++++++++++++++++++++++++++++++++++
include/linux/acpi.h | 1 +
2 files changed, 125 insertions(+)
diff --git a/drivers/acpi/arm64/gtdt.c b/drivers/acpi/arm64/gtdt.c
index d93a790..91ea6cb 100644
--- a/drivers/acpi/arm64/gtdt.c
+++ b/drivers/acpi/arm64/gtdt.c
@@ -37,6 +37,28 @@ struct acpi_gtdt_descriptor {
static struct acpi_gtdt_descriptor acpi_gtdt_desc __initdata;
+static inline void *next_platform_timer(void *platform_timer)
+{
+ struct acpi_gtdt_header *gh = platform_timer;
+
+ platform_timer += gh->length;
+ if (platform_timer < acpi_gtdt_desc.gtdt_end)
+ return platform_timer;
+
+ return NULL;
+}
+
+#define for_each_platform_timer(_g) \
+ for (_g = acpi_gtdt_desc.platform_timer; _g; \
+ _g = next_platform_timer(_g))
+
+static inline bool is_timer_block(void *platform_timer)
+{
+ struct acpi_gtdt_header *gh = platform_timer;
+
+ return gh->type == ACPI_GTDT_TYPE_TIMER_BLOCK;
+}
+
static int __init map_gt_gsi(u32 interrupt, u32 flags)
{
int trigger, polarity;
@@ -155,3 +177,105 @@ int __init acpi_gtdt_init(struct acpi_table_header *table,
return ret;
}
+
+static int __init gtdt_parse_timer_block(struct acpi_gtdt_timer_block *block,
+ struct arch_timer_mem *data)
+{
+ int i;
+ struct acpi_gtdt_timer_entry *frame;
+
+ if (!block->timer_count) {
+ pr_err(FW_BUG "GT block present, but frame count is zero.");
+ return -ENODEV;
+ }
+
+ if (block->timer_count > ARCH_TIMER_MEM_MAX_FRAMES) {
+ pr_err(FW_BUG "GT block lists %d frames, ACPI spec only allows 8\n",
+ block->timer_count);
+ return -EINVAL;
+ }
+
+ data->cntctlbase = (phys_addr_t)block->block_address;
+ /*
+ * According to "Table * CNTCTLBase memory map" of
+ * <ARM Architecture Reference Manual> for ARMv8,
+ * The size of the CNTCTLBase frame is 4KB(Offset 0x000 ? 0xFFC).
+ */
+ data->size = SZ_4K;
+ data->num_frames = block->timer_count;
+
+ frame = (void *)block + block->timer_offset;
+ if (frame + block->timer_count != (void *)block + block->header.length)
+ return -EINVAL;
+
+ /*
+ * Get the GT timer Frame data for every GT Block Timer
+ */
+ for (i = 0; i < block->timer_count; i++, frame++) {
+ if (!frame->base_address || !frame->timer_interrupt)
+ return -EINVAL;
+
+ data->frame[i].phys_irq = map_gt_gsi(frame->timer_interrupt,
+ frame->timer_flags);
+ if (data->frame[i].phys_irq <= 0) {
+ pr_warn("failed to map physical timer irq in frame %d.\n",
+ i);
+ return -EINVAL;
+ }
+
+ data->frame[i].virt_irq =
+ map_gt_gsi(frame->virtual_timer_interrupt,
+ frame->virtual_timer_flags);
+ if (data->frame[i].virt_irq <= 0) {
+ pr_warn("failed to map virtual timer irq in frame %d.\n",
+ i);
+ acpi_unregister_gsi(frame->timer_interrupt);
+ return -EINVAL;
+ }
+
+ data->frame[i].frame_nr = frame->frame_number;
+ data->frame[i].cntbase = frame->base_address;
+ /*
+ * According to "Table * CNTBaseN memory map" of
+ * <ARM Architecture Reference Manual> for ARMv8,
+ * The size of the CNTBaseN frame is 4KB(Offset 0x000 ? 0xFFC).
+ */
+ data->frame[i].size = SZ_4K;
+ }
+
+ return 0;
+}
+
+/**
+ * acpi_arch_timer_mem_init() - Get the info of all GT blocks in GTDT table.
+ * @data: the pointer to the array of struct arch_timer_mem for returning
+ * the result of parsing. The element number of this array should
+ * be platform_timer_count(the total number of platform timers).
+ * @count: The pointer of int variate for returning the number of GT
+ * blocks we have parsed.
+ *
+ * Return: 0 if success, -EINVAL/-ENODEV if error.
+ */
+int __init acpi_arch_timer_mem_init(struct arch_timer_mem *data,
+ int *timer_count)
+{
+ int ret;
+ void *platform_timer;
+
+ *timer_count = 0;
+ for_each_platform_timer(platform_timer) {
+ if (is_timer_block(platform_timer)) {
+ ret = gtdt_parse_timer_block(platform_timer, data);
+ if (ret)
+ return ret;
+ data++;
+ (*timer_count)++;
+ }
+ }
+
+ if (*timer_count)
+ pr_info("found %d memory-mapped timer block(s).\n",
+ *timer_count);
+
+ return 0;
+}
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index d201ce4..f5881de 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -581,6 +581,7 @@ int acpi_reconfig_notifier_unregister(struct notifier_block *nb);
int acpi_gtdt_init(struct acpi_table_header *table, int *platform_timer_count);
int acpi_gtdt_map_ppi(int type);
bool acpi_gtdt_c3stop(int type);
+int acpi_arch_timer_mem_init(struct arch_timer_mem *data, int *timer_count);
#endif
#else /* !CONFIG_ACPI */
--
2.9.3
^ permalink raw reply related
* [PATCH v17 14/15] clocksource/drivers/arm_arch_timer: Add GTDT support for memory-mapped timer
From: fu.wei at linaro.org @ 2016-11-25 8:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161125084623.22515-1-fu.wei@linaro.org>
From: Fu Wei <fu.wei@linaro.org>
The patch add memory-mapped timer register support by using the
information provided by the new GTDT driver of ACPI.
Signed-off-by: Fu Wei <fu.wei@linaro.org>
---
drivers/clocksource/arm_arch_timer.c | 35 ++++++++++++++++++++++++++++++++---
1 file changed, 32 insertions(+), 3 deletions(-)
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 7f059f9..1fe1c08 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -1054,10 +1054,36 @@ CLOCKSOURCE_OF_DECLARE(armv7_arch_timer_mem, "arm,armv7-timer-mem",
arch_timer_mem_of_init);
#ifdef CONFIG_ACPI_GTDT
-/* Initialize per-processor generic timer */
+static int __init arch_timer_mem_acpi_init(int platform_timer_count)
+{
+ struct arch_timer_mem *timer_mem;
+ int timer_count, i, ret;
+
+ timer_mem = kcalloc(platform_timer_count, sizeof(*timer_mem),
+ GFP_KERNEL);
+ if (!timer_mem)
+ return -ENOMEM;
+
+ ret = acpi_arch_timer_mem_init(timer_mem, &timer_count);
+ if (ret || !timer_count)
+ goto error;
+
+ for (i = 0; i < timer_count; i++) {
+ ret = arch_timer_mem_init(timer_mem);
+ if (!ret)
+ break;
+ timer_mem++;
+ }
+
+error:
+ kfree(timer_mem);
+ return ret;
+}
+
+/* Initialize per-processor generic timer and memory-mapped timer(if present) */
static int __init arch_timer_acpi_init(struct acpi_table_header *table)
{
- int ret;
+ int ret, platform_timer_count;
if (arch_timers_present & ARCH_TIMER_TYPE_CP15) {
pr_warn("already initialized, skipping\n");
@@ -1066,7 +1092,7 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table)
arch_timers_present |= ARCH_TIMER_TYPE_CP15;
- ret = acpi_gtdt_init(table, NULL);
+ ret = acpi_gtdt_init(table, &platform_timer_count);
if (ret) {
pr_err("Failed to init GTDT table.\n");
return ret;
@@ -1099,6 +1125,9 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table)
if (ret)
return ret;
+ if (arch_timer_mem_acpi_init(platform_timer_count))
+ pr_err("Failed to initialize memory-mapped timer.\n");
+
return arch_timer_common_init();
}
CLOCKSOURCE_ACPI_DECLARE(arch_timer, ACPI_SIG_GTDT, arch_timer_acpi_init);
--
2.9.3
^ permalink raw reply related
* [PATCH v17 15/15] acpi/arm64: Add SBSA Generic Watchdog support in GTDT driver
From: fu.wei at linaro.org @ 2016-11-25 8:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161125084623.22515-1-fu.wei@linaro.org>
From: Fu Wei <fu.wei@linaro.org>
This driver adds support for parsing SBSA Generic Watchdog timer
in GTDT, parse all info in SBSA Generic Watchdog Structure in GTDT,
and creating a platform device with that information.
This allows the operating system to obtain device data from the
resource of platform device. The platform device named "sbsa-gwdt"
can be used by the ARM SBSA Generic Watchdog driver.
Signed-off-by: Fu Wei <fu.wei@linaro.org>
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
Tested-by: Xiongfeng Wang <wangxiongfeng2@huawei.com>
---
drivers/acpi/arm64/gtdt.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++
drivers/watchdog/Kconfig | 1 +
2 files changed, 94 insertions(+)
diff --git a/drivers/acpi/arm64/gtdt.c b/drivers/acpi/arm64/gtdt.c
index 91ea6cb..22d3659 100644
--- a/drivers/acpi/arm64/gtdt.c
+++ b/drivers/acpi/arm64/gtdt.c
@@ -14,6 +14,7 @@
#include <linux/acpi.h>
#include <linux/init.h>
#include <linux/kernel.h>
+#include <linux/platform_device.h>
#include <clocksource/arm_arch_timer.h>
@@ -59,6 +60,13 @@ static inline bool is_timer_block(void *platform_timer)
return gh->type == ACPI_GTDT_TYPE_TIMER_BLOCK;
}
+static inline bool is_watchdog(void *platform_timer)
+{
+ struct acpi_gtdt_header *gh = platform_timer;
+
+ return gh->type == ACPI_GTDT_TYPE_WATCHDOG;
+}
+
static int __init map_gt_gsi(u32 interrupt, u32 flags)
{
int trigger, polarity;
@@ -279,3 +287,88 @@ int __init acpi_arch_timer_mem_init(struct arch_timer_mem *data,
return 0;
}
+
+/*
+ * Initialize a SBSA generic Watchdog platform device info from GTDT
+ */
+static int __init gtdt_import_sbsa_gwdt(struct acpi_gtdt_watchdog *wd,
+ int index)
+{
+ struct platform_device *pdev;
+ int irq = map_gt_gsi(wd->timer_interrupt, wd->timer_flags);
+ int no_irq = 1;
+
+ /*
+ * According to SBSA specification the size of refresh and control
+ * frames of SBSA Generic Watchdog is SZ_4K(Offset 0x000 ? 0xFFF).
+ */
+ struct resource res[] = {
+ DEFINE_RES_MEM(wd->control_frame_address, SZ_4K),
+ DEFINE_RES_MEM(wd->refresh_frame_address, SZ_4K),
+ DEFINE_RES_IRQ(irq),
+ };
+
+ pr_debug("found a Watchdog (0x%llx/0x%llx gsi:%u flags:0x%x).\n",
+ wd->refresh_frame_address, wd->control_frame_address,
+ wd->timer_interrupt, wd->timer_flags);
+
+ if (!(wd->refresh_frame_address && wd->control_frame_address)) {
+ pr_err(FW_BUG "failed to get the Watchdog base address.\n");
+ return -EINVAL;
+ }
+
+ if (!wd->timer_interrupt)
+ pr_warn(FW_BUG "failed to get the Watchdog interrupt.\n");
+ else if (irq <= 0)
+ pr_warn("failed to map the Watchdog interrupt.\n");
+ else
+ no_irq = 0;
+
+ /*
+ * Add a platform device named "sbsa-gwdt" to match the platform driver.
+ * "sbsa-gwdt": SBSA(Server Base System Architecture) Generic Watchdog
+ * The platform driver (like drivers/watchdog/sbsa_gwdt.c)can get device
+ * info below by matching this name.
+ */
+ pdev = platform_device_register_simple("sbsa-gwdt", index, res,
+ ARRAY_SIZE(res) - no_irq);
+ if (IS_ERR(pdev)) {
+ acpi_unregister_gsi(wd->timer_interrupt);
+ return PTR_ERR(pdev);
+ }
+
+ return 0;
+}
+
+static int __init gtdt_sbsa_gwdt_init(void)
+{
+ int ret, i = 0;
+ void *platform_timer;
+ struct acpi_table_header *table;
+
+ if (acpi_disabled)
+ return 0;
+
+ if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_GTDT, 0, &table)))
+ return -EINVAL;
+
+ ret = acpi_gtdt_init(table, NULL);
+ if (ret)
+ return ret;
+
+ for_each_platform_timer(platform_timer) {
+ if (is_watchdog(platform_timer)) {
+ ret = gtdt_import_sbsa_gwdt(platform_timer, i);
+ if (ret)
+ break;
+ i++;
+ }
+ }
+
+ if (i)
+ pr_info("found %d SBSA generic Watchdog(s).\n", i);
+
+ return ret;
+}
+
+device_initcall(gtdt_sbsa_gwdt_init);
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index fdd3228..e5ba1f0 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -218,6 +218,7 @@ config ARM_SBSA_WATCHDOG
tristate "ARM SBSA Generic Watchdog"
depends on ARM64
depends on ARM_ARCH_TIMER
+ depends on ACPI_GTDT || !ACPI
select WATCHDOG_CORE
help
ARM SBSA Generic Watchdog has two stage timeouts:
--
2.9.3
^ permalink raw reply related
* [PATCH 1/1] net: macb: fix the RX queue reset in macb_rx()
From: Cyrille Pitchen @ 2016-11-25 8:49 UTC (permalink / raw)
To: linux-arm-kernel
On macb only (not gem), when a RX queue corruption was detected from
macb_rx(), the RX queue was reset: during this process the RX ring
buffer descriptor was initialized by macb_init_rx_ring() but we forgot
to also set bp->rx_tail to 0.
Indeed, when processing the received frames, bp->rx_tail provides the
macb driver with the index in the RX ring buffer of the next buffer to
process. So when the whole ring buffer is reset we must also reset
bp->rx_tail so the driver is synchronized again with the hardware.
Since macb_init_rx_ring() is called from many locations, currently from
macb_rx() and macb_init_rings(), we'd rather add the "bp->rx_tail = 0;"
line inside macb_init_rx_ring() than add the very same line after each
call of this function.
Without this fix, the rx queue is not reset properly to recover from
queue corruption and connection drop may occur.
Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
Fixes: 9ba723b081a2 ("net: macb: remove BUG_ON() and reset the queue to handle RX errors")
---
drivers/net/ethernet/cadence/macb.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
index 0e489bb82456..8ee303b8da08 100644
--- a/drivers/net/ethernet/cadence/macb.c
+++ b/drivers/net/ethernet/cadence/macb.c
@@ -991,6 +991,7 @@ static inline void macb_init_rx_ring(struct macb *bp)
addr += bp->rx_buffer_size;
}
bp->rx_ring[bp->rx_ring_size - 1].addr |= MACB_BIT(RX_WRAP);
+ bp->rx_tail = 0;
}
static int macb_rx(struct macb *bp, int budget)
@@ -1736,8 +1737,6 @@ static void macb_init_rings(struct macb *bp)
bp->queues[0].tx_head = 0;
bp->queues[0].tx_tail = 0;
bp->queues[0].tx_ring[bp->tx_ring_size - 1].ctrl |= MACB_BIT(TX_WRAP);
-
- bp->rx_tail = 0;
}
static void macb_reset_hw(struct macb *bp)
--
2.7.4
^ permalink raw reply related
* Synopsys Ethernet QoS Driver
From: Giuseppe CAVALLARO @ 2016-11-25 8:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <f4dd5d22-4467-d046-6b65-2a28f3fc5a7c@synopsys.com>
On 11/23/2016 12:43 PM, Joao Pinto wrote:
>> > Rabin Vincent can review and test that the port works properly on our Artpec-chips that use dwc_eth_qos.c today.
>> >
>> > The main porting step is to implement the device tree binding in bindings/net/snps,dwc-qos-ethernet.txt. Also our chip has a strict requirement that the phy is enabled when the SWR reset bit is set (it needs a tx clock to complete the reset).
>> >
>> > - Lars
> Ok, I will do the task.
>
> @Peppe: Agree with the plan?
Agree
peppe
^ permalink raw reply
* [PATCH renesas-next 1/3] ARM: dts: r8a73a4: Use SoC-specific compat string for mmcif
From: Geert Uytterhoeven @ 2016-11-25 8:58 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480018514-31718-2-git-send-email-horms+renesas@verge.net.au>
On Thu, Nov 24, 2016 at 9:15 PM, Simon Horman
<horms+renesas@verge.net.au> wrote:
> Use the SoC-specific compat string for mmcif in DT for the r8a73a4 SoC.
> This is in keeping with the use of compat strings for mmcif for other
> Renesas ARM based SoCs.
>
> Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
Acked-by: Geert Uytterhoeven <geert+renesas@glider.be>
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert at linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* [PATCH renesas-next 2/3] ARM: dts: r8a7778: Use SoC-specific compat string for mmcif
From: Geert Uytterhoeven @ 2016-11-25 8:59 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480018514-31718-3-git-send-email-horms+renesas@verge.net.au>
On Thu, Nov 24, 2016 at 9:15 PM, Simon Horman
<horms+renesas@verge.net.au> wrote:
> Use the SoC-specific compat string for mmcif in DT for the r8a7778 SoC.
> This is in keeping with the use of compat strings for mmcif for other
> Renesas ARM based SoCs.
>
> Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
Acked-by: Geert Uytterhoeven <geert+renesas@glider.be>
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert at linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* [PATCH renesas-next 3/3] ARM: dts: sh73a0: Use SoC-specific compat string for mmcif
From: Geert Uytterhoeven @ 2016-11-25 8:59 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480018514-31718-4-git-send-email-horms+renesas@verge.net.au>
On Thu, Nov 24, 2016 at 9:15 PM, Simon Horman
<horms+renesas@verge.net.au> wrote:
> Use the SoC-specific compat string for mmcif in DT for the sh73a0 SoC.
> This is in keeping with the use of compat strings for mmcif for other
> Renesas ARM based SoCs.
>
> Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
Acked-by: Geert Uytterhoeven <geert+renesas@glider.be>
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert at linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* [net-next PATCH v1 0/2] stmmac: dwmac-meson8b: configurable RGMII TX delay
From: Giuseppe CAVALLARO @ 2016-11-25 8:59 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480003681.17538.142.camel@baylibre.com>
On 11/24/2016 5:08 PM, Jerome Brunet wrote:
> On Thu, 2016-11-24 at 15:34 +0100, Martin Blumenstingl wrote:
>> Currently the dwmac-meson8b stmmac glue driver uses a hardcoded 1/4
>> cycle TX clock delay. This seems to work fine for many boards (for
>> example Odroid-C2 or Amlogic's reference boards) but there are some
>> others where TX traffic is simply broken.
>> There are probably multiple reasons why it's working on some boards
>> while it's broken on others:
>> - some of Amlogic's reference boards are using a Micrel PHY
>> - hardware circuit design
>> - maybe more...
>>
>> This raises a question though:
>> Which device is supposed to enable the TX delay when both MAC and PHY
>> support it? And should we implement it for each PHY / MAC separately
>> or should we think about a more generic solution (currently it's not
>> possible to disable the TX delay generated by the RTL8211F PHY via
>> devicetree when using phy-mode "rgmii")?
>>
>> iperf3 results on my Mecool BB2 board (Meson GXM, RTL8211F PHY) with
>> TX clock delay disabled on the MAC (as it's enabled in the PHY
>> driver).
>> TX throughput was virtually zero before:
>> $ iperf3 -c 192.168.1.100 -R
>> Connecting to host 192.168.1.100, port 5201
>> Reverse mode, remote host 192.168.1.100 is sending
>> [ 4] local 192.168.1.206 port 52828 connected to 192.168.1.100 port
>> 5201
>> [ ID] Interval Transfer Bandwidth
>> [ 4] 0.00-1.00 sec 108 MBytes 901
>> Mbits/sec
>> [ 4] 1.00-2.00 sec 94.2 MBytes 791
>> Mbits/sec
>> [ 4] 2.00-3.00 sec 96.5 MBytes 810
>> Mbits/sec
>> [ 4] 3.00-4.00 sec 96.2 MBytes 808
>> Mbits/sec
>> [ 4] 4.00-5.00 sec 96.6 MBytes 810
>> Mbits/sec
>> [ 4] 5.00-6.00 sec 96.5 MBytes 810
>> Mbits/sec
>> [ 4] 6.00-7.00 sec 96.6 MBytes 810
>> Mbits/sec
>> [ 4] 7.00-8.00 sec 96.5 MBytes 809
>> Mbits/sec
>> [ 4] 8.00-9.00 sec 105 MBytes 884
>> Mbits/sec
>> [ 4] 9.00-10.00 sec 111 MBytes 934
>> Mbits/sec
>> - - - - - - - - - - - - - - - - - - - - - - - - -
>> [ ID] Interval Transfer Bandwidth Retr
>> [ 4] 0.00-10.00 sec 1000 MBytes 839
>> Mbits/sec 0 sender
>> [ 4] 0.00-10.00 sec 998 MBytes 837
>> Mbits/sec receiver
>>
>> iperf Done.
>> $ iperf3 -c 192.168.1.100
>> Connecting to host 192.168.1.100, port 5201
>> [ 4] local 192.168.1.206 port 52832 connected to 192.168.1.100 port
>> 5201
>> [ ID] Interval Transfer Bandwidth Retr Cwnd
>> [ 4] 0.00-1.01 sec 99.5 MBytes 829 Mbits/sec 117 139
>> KBytes
>> [ 4] 1.01-2.00 sec 105 MBytes 884 Mbits/sec 129 70.7
>> KBytes
>> [ 4] 2.00-3.01 sec 107 MBytes 889 Mbits/sec 106 187
>> KBytes
>> [ 4] 3.01-4.01 sec 105 MBytes 878 Mbits/sec 92 143
>> KBytes
>> [ 4] 4.01-5.00 sec 105 MBytes 882 Mbits/sec 140 129
>> KBytes
>> [ 4] 5.00-6.01 sec 106 MBytes 883 Mbits/sec 115 195
>> KBytes
>> [ 4] 6.01-7.00 sec 102 MBytes 863 Mbits/sec 133 70.7
>> KBytes
>> [ 4] 7.00-8.01 sec 106 MBytes 884 Mbits/sec 143 97.6
>> KBytes
>> [ 4] 8.01-9.01 sec 104 MBytes 875 Mbits/sec 124 107
>> KBytes
>> [ 4] 9.01-10.01 sec 105 MBytes 876 Mbits/sec 90 139
>> KBytes
>> - - - - - - - - - - - - - - - - - - - - - - - - -
>> [ ID] Interval Transfer Bandwidth Retr
>> [ 4] 0.00-10.01 sec 1.02 GBytes 874
>> Mbits/sec 1189 sender
>> [ 4] 0.00-10.01 sec 1.02 GBytes 873
>> Mbits/sec receiver
>>
>
> Cool, one more board working ;)
> I tried your patch on another board (MXQ_V2.1, with sheep printed on
> the PCB). It 's not improving the situation for this one unfortunately.
> Actually I already tried playing with the TX delay on the MAC and PHY
> but I could get any good results with the boards I have.
>
> It is strange that we can adjust the delay by 2ns steps, when delay
> seens by the phy should be 2ns ...
>
Ok, as said, I could expect that extra delay was needed on GiGa.
FYI, on ST platforms, this extra delay was added in the pintctrl
dtsi. I mean, in some way, ad-hoc setup was solved at device-tree
level. Usually, extra delay could depend on the PCB.
peppe
>> iperf Done.
>>
>>
>> Martin Blumenstingl (2):
>> net: dt-bindings: add RGMII TX delay configuration to meson8b-dwmac
>> net: stmmac: dwmac-meson8b: make the RGMII TX delay configurable
>>
>> Documentation/devicetree/bindings/net/meson-dwmac.txt | 11
>> +++++++++++
>> drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c | 16
>> +++++++++++-----
>> include/dt-bindings/net/dwmac-meson8b.h | 18
>> ++++++++++++++++++
>> 3 files changed, 40 insertions(+), 5 deletions(-)
>> create mode 100644 include/dt-bindings/net/dwmac-meson8b.h
>>
>
^ permalink raw reply
* RPI3 doesn't boot in ARM64 mode on linux-next
From: Michael Zoran @ 2016-11-25 9:05 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAKv+Gu-SNWpAskP19Swr_YsW=uATuNXkvdWKBpWcoVC4ndFASQ@mail.gmail.com>
On Fri, 2016-11-25 at 08:12 +0000, Ard Biesheuvel wrote:
> On 25 November 2016 at 02:31, Michael Zoran <mzoran@crowfest.net>
> wrote:
> > Last night I did a build of linux-next and I'm finding that I can
> > no
> > longer get my RPI 3 to boot in arm64 mode anymore.??It seems to be
> > hanging very early in the boot process.
> >
> > I know linux-next is going through a very large number of changes
> > now,
> > so does anybody know if arm64(not just the RPI 3) is just broken in
> > general at this point? 4.9rc6 is working fine.
> >
> > I don't have a JTAG debugger, so it's a bit hard for me to
> > debug.??I've
> > actually been looking for a decent cheap JTAG debugger for awhile
> > now,
> > so if anybody knows of one in the < $300.00 range it might be a
> > good
> > self Christmas present.
> >
>
> Are you using earlycon?
No, but that's a good thing for me to try next. I also found the
Segger J-Link on the web for $60 that I bought. Hopefully one or the
other will work.
^ permalink raw reply
* [PATCH 00/10] add support for VBUS max current and min voltage limits AXP20X and AXP22X PMICs
From: Quentin Schulz @ 2016-11-25 9:09 UTC (permalink / raw)
To: linux-arm-kernel
The X-Powers AXP209 and AXP20X PMICs are able to set a limit for the VBUS power
supply for both max current and min voltage supplied. This series of patch adds
the possibility to set these limits from sysfs.
Also, the AXP223 PMIC shares most of its behaviour with the AXP221 but the
former can set the VBUS power supply max current to 100mA, unlike the latter.
The AXP223 VBUS power supply driver used to probe on the AXP221 compatible. This
series of patch introduces a new compatible for the AXP223 to be able to set the
current max limit to 100mA.
With that new compatible, boards having the AXP223 see their DT updated to use
the VBUS power supply driver with the correct compatible.
This series of patch also migrates from of_device_is_compatible function to the
data field of of_device_id to identify the compatible used to probe. This
improves the code readability.
Quentin Schulz (10):
power: supply: axp20x_usb_power: use of_device_id data field instead
of device_is_compatible
power: supply: axp20x_usb_power: set min voltage and max current from
sysfs
Documentation: DT: binding: axp20x_usb_power: add axp223 compatible
power: supply: axp20x_usb_power: add 100mA max current limit for
AXP223
mfd: axp20x: add separate MFD cell for AXP223
ARM: dtsi: add DTSI for AXP223
ARM: dts: sun8i-a33-olinuxino: use AXP223 DTSI
ARM: dts: sun8i-a33-sinlinx-sina33: use AXP223 DTSI
ARM: dts: sun8i-r16-parrot: use AXP223 DTSI
ARM: dtsi: sun8i-reference-design-tablet: use AXP223 DTSI
.../bindings/power/supply/axp20x_usb_power.txt | 1 +
arch/arm/boot/dts/axp223.dtsi | 55 ++++++++++
arch/arm/boot/dts/sun8i-a33-olinuxino.dts | 2 +-
arch/arm/boot/dts/sun8i-a33-sinlinx-sina33.dts | 2 +-
arch/arm/boot/dts/sun8i-r16-parrot.dts | 2 +-
.../boot/dts/sun8i-reference-design-tablet.dtsi | 2 +-
drivers/mfd/axp20x.c | 22 +++-
drivers/power/supply/axp20x_usb_power.c | 120 +++++++++++++++++----
include/linux/mfd/axp20x.h | 3 +
9 files changed, 186 insertions(+), 23 deletions(-)
create mode 100644 arch/arm/boot/dts/axp223.dtsi
--
2.9.3
^ permalink raw reply
* [PATCH 01/10] power: supply: axp20x_usb_power: use of_device_id data field instead of device_is_compatible
From: Quentin Schulz @ 2016-11-25 9:09 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161125090921.23138-1-quentin.schulz@free-electrons.com>
This replaces calls to of_device_is_compatible to check data field of
of_device_id matched when probing the driver.
Signed-off-by: Quentin Schulz <quentin.schulz@free-electrons.com>
---
drivers/power/supply/axp20x_usb_power.c | 39 ++++++++++++++++++++-------------
1 file changed, 24 insertions(+), 15 deletions(-)
diff --git a/drivers/power/supply/axp20x_usb_power.c b/drivers/power/supply/axp20x_usb_power.c
index 6af6feb..b19754e 100644
--- a/drivers/power/supply/axp20x_usb_power.c
+++ b/drivers/power/supply/axp20x_usb_power.c
@@ -17,6 +17,7 @@
#include <linux/mfd/axp20x.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
#include <linux/regmap.h>
@@ -45,6 +46,7 @@ struct axp20x_usb_power {
struct device_node *np;
struct regmap *regmap;
struct power_supply *supply;
+ int axp20x_id;
};
static irqreturn_t axp20x_usb_power_irq(int irq, void *devid)
@@ -86,8 +88,7 @@ static int axp20x_usb_power_get_property(struct power_supply *psy,
switch (v & AXP20X_VBUS_CLIMIT_MASK) {
case AXP20X_VBUC_CLIMIT_100mA:
- if (of_device_is_compatible(power->np,
- "x-powers,axp202-usb-power-supply")) {
+ if (power->axp20x_id == AXP202_ID) {
val->intval = 100000;
} else {
val->intval = -1; /* No 100mA limit */
@@ -130,8 +131,7 @@ static int axp20x_usb_power_get_property(struct power_supply *psy,
val->intval = POWER_SUPPLY_HEALTH_GOOD;
- if (of_device_is_compatible(power->np,
- "x-powers,axp202-usb-power-supply")) {
+ if (power->axp20x_id == AXP202_ID) {
ret = regmap_read(power->regmap,
AXP20X_USB_OTG_STATUS, &v);
if (ret)
@@ -189,6 +189,17 @@ static const struct power_supply_desc axp22x_usb_power_desc = {
.get_property = axp20x_usb_power_get_property,
};
+static const struct of_device_id axp20x_usb_power_match[] = {
+ {
+ .compatible = "x-powers,axp202-usb-power-supply",
+ .data = (void *)AXP202_ID,
+ }, {
+ .compatible = "x-powers,axp221-usb-power-supply",
+ .data = (void *)AXP221_ID,
+ }, { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, axp20x_usb_power_match);
+
static int axp20x_usb_power_probe(struct platform_device *pdev)
{
struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
@@ -200,11 +211,16 @@ static int axp20x_usb_power_probe(struct platform_device *pdev)
"VBUS_PLUGIN", "VBUS_REMOVAL", NULL };
static const char * const *irq_names;
const struct power_supply_desc *usb_power_desc;
+ const struct of_device_id *of_id;
int i, irq, ret;
if (!of_device_is_available(pdev->dev.of_node))
return -ENODEV;
+ of_id = of_match_device(axp20x_usb_power_match, &pdev->dev);
+ if (!of_id)
+ return -ENODEV;
+
if (!axp20x) {
dev_err(&pdev->dev, "Parent drvdata not set\n");
return -EINVAL;
@@ -214,11 +230,12 @@ static int axp20x_usb_power_probe(struct platform_device *pdev)
if (!power)
return -ENOMEM;
+ power->axp20x_id = (int)of_id->data;
+
power->np = pdev->dev.of_node;
power->regmap = axp20x->regmap;
- if (of_device_is_compatible(power->np,
- "x-powers,axp202-usb-power-supply")) {
+ if (power->axp20x_id == AXP202_ID) {
/* Enable vbus valid checking */
ret = regmap_update_bits(power->regmap, AXP20X_VBUS_MON,
AXP20X_VBUS_MON_VBUS_VALID,
@@ -235,8 +252,7 @@ static int axp20x_usb_power_probe(struct platform_device *pdev)
usb_power_desc = &axp20x_usb_power_desc;
irq_names = axp20x_irq_names;
- } else if (of_device_is_compatible(power->np,
- "x-powers,axp221-usb-power-supply")) {
+ } else if (power->axp20x_id == AXP221_ID) {
usb_power_desc = &axp22x_usb_power_desc;
irq_names = axp22x_irq_names;
} else {
@@ -272,13 +288,6 @@ static int axp20x_usb_power_probe(struct platform_device *pdev)
return 0;
}
-static const struct of_device_id axp20x_usb_power_match[] = {
- { .compatible = "x-powers,axp202-usb-power-supply" },
- { .compatible = "x-powers,axp221-usb-power-supply" },
- { }
-};
-MODULE_DEVICE_TABLE(of, axp20x_usb_power_match);
-
static struct platform_driver axp20x_usb_power_driver = {
.probe = axp20x_usb_power_probe,
.driver = {
--
2.9.3
^ permalink raw reply related
* [PATCH 02/10] power: supply: axp20x_usb_power: set min voltage and max current from sysfs
From: Quentin Schulz @ 2016-11-25 9:09 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161125090921.23138-1-quentin.schulz@free-electrons.com>
AXP20X and AXP22X PMICs allow setting the min voltage and max current of
VBUS power supply. This adds entries in sysfs to allow to do so.
Signed-off-by: Quentin Schulz <quentin.schulz@free-electrons.com>
---
drivers/power/supply/axp20x_usb_power.c | 72 +++++++++++++++++++++++++++++++++
include/linux/mfd/axp20x.h | 3 ++
2 files changed, 75 insertions(+)
diff --git a/drivers/power/supply/axp20x_usb_power.c b/drivers/power/supply/axp20x_usb_power.c
index b19754e..638cb52 100644
--- a/drivers/power/supply/axp20x_usb_power.c
+++ b/drivers/power/supply/axp20x_usb_power.c
@@ -155,6 +155,74 @@ static int axp20x_usb_power_get_property(struct power_supply *psy,
return 0;
}
+static int axp20x_usb_power_set_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ const union power_supply_propval *val)
+{
+ struct axp20x_usb_power *power = power_supply_get_drvdata(psy);
+ int ret, val1;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_VOLTAGE_MIN:
+ switch (val->intval) {
+ case 4000000:
+ case 4100000:
+ case 4200000:
+ case 4300000:
+ case 4400000:
+ case 4500000:
+ case 4600000:
+ case 4700000:
+ val1 = (val->intval - 4000000) / 100000;
+ ret = regmap_update_bits(power->regmap,
+ AXP20X_VBUS_IPSOUT_MGMT,
+ AXP20X_VBUS_VHOLD_MASK,
+ val1 << 3);
+ if (ret)
+ return ret;
+
+ return 0;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+
+ case POWER_SUPPLY_PROP_CURRENT_MAX:
+ switch (val->intval) {
+ case 100000:
+ if (power->axp20x_id == AXP221_ID)
+ return -EINVAL;
+ case 500000:
+ case 900000:
+ val1 = (900000 - val->intval) / 400000;
+ ret = regmap_update_bits(power->regmap,
+ AXP20X_VBUS_IPSOUT_MGMT,
+ AXP20X_VBUS_CLIMIT_MASK, val1);
+ if (ret)
+ return ret;
+
+ return 0;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int axp20x_usb_power_prop_writeable(struct power_supply *psy,
+ enum power_supply_property psp)
+{
+ return psp == POWER_SUPPLY_PROP_VOLTAGE_MIN ||
+ psp == POWER_SUPPLY_PROP_CURRENT_MAX;
+}
+
static enum power_supply_property axp20x_usb_power_properties[] = {
POWER_SUPPLY_PROP_HEALTH,
POWER_SUPPLY_PROP_PRESENT,
@@ -178,7 +246,9 @@ static const struct power_supply_desc axp20x_usb_power_desc = {
.type = POWER_SUPPLY_TYPE_USB,
.properties = axp20x_usb_power_properties,
.num_properties = ARRAY_SIZE(axp20x_usb_power_properties),
+ .property_is_writeable = axp20x_usb_power_prop_writeable,
.get_property = axp20x_usb_power_get_property,
+ .set_property = axp20x_usb_power_set_property,
};
static const struct power_supply_desc axp22x_usb_power_desc = {
@@ -186,7 +256,9 @@ static const struct power_supply_desc axp22x_usb_power_desc = {
.type = POWER_SUPPLY_TYPE_USB,
.properties = axp22x_usb_power_properties,
.num_properties = ARRAY_SIZE(axp22x_usb_power_properties),
+ .property_is_writeable = axp20x_usb_power_prop_writeable,
.get_property = axp20x_usb_power_get_property,
+ .set_property = axp20x_usb_power_set_property,
};
static const struct of_device_id axp20x_usb_power_match[] = {
diff --git a/include/linux/mfd/axp20x.h b/include/linux/mfd/axp20x.h
index fec597f..8883595 100644
--- a/include/linux/mfd/axp20x.h
+++ b/include/linux/mfd/axp20x.h
@@ -56,6 +56,9 @@ enum {
#define AXP20X_LDO24_V_OUT 0x28
#define AXP20X_LDO3_V_OUT 0x29
#define AXP20X_VBUS_IPSOUT_MGMT 0x30
+
+#define AXP20X_VBUS_VHOLD_MASK GENMASK(5, 3)
+
#define AXP20X_V_OFF 0x31
#define AXP20X_OFF_CTRL 0x32
#define AXP20X_CHRG_CTRL1 0x33
--
2.9.3
^ permalink raw reply related
* [PATCH 03/10] Documentation: DT: binding: axp20x_usb_power: add axp223 compatible
From: Quentin Schulz @ 2016-11-25 9:09 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161125090921.23138-1-quentin.schulz@free-electrons.com>
This adds the "x-powers,axp223-usb-power-supply" to the list of
compatibles for AXP20X VBUS power supply driver.
Signed-off-by: Quentin Schulz <quentin.schulz@free-electrons.com>
---
Documentation/devicetree/bindings/power/supply/axp20x_usb_power.txt | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/power/supply/axp20x_usb_power.txt b/Documentation/devicetree/bindings/power/supply/axp20x_usb_power.txt
index f1d7bee..bf3953c 100644
--- a/Documentation/devicetree/bindings/power/supply/axp20x_usb_power.txt
+++ b/Documentation/devicetree/bindings/power/supply/axp20x_usb_power.txt
@@ -3,6 +3,7 @@ AXP20x USB power supply
Required Properties:
-compatible: One of: "x-powers,axp202-usb-power-supply"
"x-powers,axp221-usb-power-supply"
+ "x-powers,axp223-usb-power-supply"
This node is a subnode of the axp20x PMIC.
--
2.9.3
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox