hi,
The patches in the series are work in progress and as discussed with Al Stone and Hanjun include changes in the GTDT acpi table to add missing elements for ARM platforms. Elements added are Timer frequency, interrupt count(currently 8 supported), timer ID(This will be used to invoke the correct controller).
Still more TODO's are identified. * To add timer clock names. * if this __init invoking mechanism is finalised then other similar devices can use this like clock, GIC etc. * GTDT can ultimately be made CTDT(Common timer descriptor table) to other classes of timers like external exynos MCT.
Changes in V2: * Added new fields in GTDT acpi table. * Infrastructure to invoke the correct timer controller.
Thanks in advance. Amit
Amit Daniel Kachhap (6): irqdomain: Add a new API irq_create_default_mapping ACPI: ARM: Update acpi_register_gsi to register with the core IRQ subsystem irqchip: gic: Fix to make dt node check optional in case of ACPI acpi: gtdt: Update GTDT tables to add more fields clocksource:acpi: Add macro CLOCKSOURCE_ACPI_DECLARE clocksource: arch_timer: acpi: Use GTDT table to gather data
drivers/acpi/plat/arm/boot.c | 27 +++++++- drivers/clocksource/arm_arch_timer.c | 111 +++++++++++++++++++++++++++++----- drivers/clocksource/clksrc-of.c | 32 ++++++++++ drivers/irqchip/irq-gic.c | 2 + include/acpi/actbl3.h | 22 +++++++ include/asm-generic/vmlinux.lds.h | 6 ++ include/linux/clocksource.h | 13 ++++ include/linux/irqdomain.h | 2 + kernel/irq/irqdomain.c | 35 +++++++++++ 9 files changed, 232 insertions(+), 18 deletions(-)
This new API is similar to irq_create_of_mapping but uses the default attached irqdomain.
Signed-off-by: Amit Daniel Kachhap amit.daniel@samsung.com --- include/linux/irqdomain.h | 2 ++ kernel/irq/irqdomain.c | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 0 deletions(-)
diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h index c983ed1..356e869 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h @@ -175,6 +175,8 @@ extern void irq_domain_associate_many(struct irq_domain *domain,
extern unsigned int irq_create_mapping(struct irq_domain *host, irq_hw_number_t hwirq); +extern unsigned int irq_create_default_mapping(const u32 *intspec, + unsigned int intsize); extern void irq_dispose_mapping(unsigned int virq);
/** diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index 706724e..1d88d7f 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -502,6 +502,41 @@ unsigned int irq_create_of_mapping(struct device_node *controller, } EXPORT_SYMBOL_GPL(irq_create_of_mapping);
+unsigned int irq_create_default_mapping(const u32 *intspec, + unsigned int intsize) +{ + struct irq_domain *domain; + irq_hw_number_t hwirq; + unsigned int type = IRQ_TYPE_NONE; + unsigned int virq; + + domain = irq_default_domain; + if (!domain) { + pr_warn("no irq domain found !\n"); + return 0; + } + + /* If domain has no translation, then we assume interrupt line */ + if (domain->ops->xlate == NULL) + hwirq = intspec[0]; + else { + if (domain->ops->xlate(domain, NULL, intspec, intsize, + &hwirq, &type)) + return 0; + } + + /* Create mapping */ + virq = irq_create_mapping(domain, hwirq); + if (!virq) + return virq; + + /* Set type if specified and different than the current one */ + if (type != IRQ_TYPE_NONE && + type != irq_get_trigger_type(virq)) + irq_set_irq_type(virq, type); + return virq; +} +EXPORT_SYMBOL_GPL(irq_create_default_mapping); /** * irq_dispose_mapping() - Unmap an interrupt * @virq: linux irq number of the interrupt to unmap
This API is similar to DT based irq_of_parse_and_map but does link parent/child IRQ controllers. This is tested for primary GIC PPI and GIC SPI interrupts and not for secondary child irq controllers.
Signed-off-by: Amit Daniel Kachhap amit.daniel@samsung.com --- drivers/acpi/plat/arm/boot.c | 27 ++++++++++++++++++++++++--- 1 files changed, 24 insertions(+), 3 deletions(-)
diff --git a/drivers/acpi/plat/arm/boot.c b/drivers/acpi/plat/arm/boot.c index 4fcdd9f..53937d8 100644 --- a/drivers/acpi/plat/arm/boot.c +++ b/drivers/acpi/plat/arm/boot.c @@ -247,6 +247,7 @@ static int acpi_register_gsi_ioapic(struct device *dev, u32 gsi, int (*__acpi_register_gsi)(struct device *dev, u32 gsi, int trigger, int polarity) = acpi_register_gsi_pic;
+#define MAX_SPECIFIER_SIZE 4 /* * success: return IRQ number (>=0) * failure: return < 0 @@ -255,11 +256,31 @@ int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity) { unsigned int irq; unsigned int plat_gsi = gsi; + u32 specifier[MAX_SPECIFIER_SIZE];
- plat_gsi = (*__acpi_register_gsi)(dev, gsi, trigger, polarity); - - irq = gsi_to_irq(plat_gsi); + memset(specifier, 0, sizeof(specifier)); + if (gsi <= 32) { + /* PPI interrupt */ + specifier[0] = 1; + }
+ specifier[1] = gsi; + if (trigger == ACPI_EDGE_SENSITIVE && + polarity == ACPI_ACTIVE_LOW) + specifier[2] = IRQ_TYPE_EDGE_FALLING; + else if (trigger == ACPI_EDGE_SENSITIVE && + polarity == ACPI_ACTIVE_HIGH) + specifier[2] = IRQ_TYPE_EDGE_RISING; + else if (trigger == ACPI_LEVEL_SENSITIVE && + polarity == ACPI_ACTIVE_LOW) + specifier[2] = IRQ_TYPE_LEVEL_LOW; + else if (trigger == ACPI_LEVEL_SENSITIVE && + polarity == ACPI_ACTIVE_HIGH) + specifier[2] = IRQ_TYPE_LEVEL_HIGH; + else + specifier[2] = IRQ_TYPE_NONE; + + irq = irq_create_default_mapping(specifier, 3); return irq; } EXPORT_SYMBOL_GPL(acpi_register_gsi);
On 2013-10-9 19:47, Amit Daniel Kachhap wrote:
This API is similar to DT based irq_of_parse_and_map but does link parent/child IRQ controllers. This is tested for primary GIC PPI and GIC SPI interrupts and not for secondary child irq controllers.
Signed-off-by: Amit Daniel Kachhap amit.daniel@samsung.com
drivers/acpi/plat/arm/boot.c | 27 ++++++++++++++++++++++++--- 1 files changed, 24 insertions(+), 3 deletions(-)
diff --git a/drivers/acpi/plat/arm/boot.c b/drivers/acpi/plat/arm/boot.c index 4fcdd9f..53937d8 100644 --- a/drivers/acpi/plat/arm/boot.c +++ b/drivers/acpi/plat/arm/boot.c @@ -247,6 +247,7 @@ static int acpi_register_gsi_ioapic(struct device *dev, u32 gsi, int (*__acpi_register_gsi)(struct device *dev, u32 gsi, int trigger, int polarity) = acpi_register_gsi_pic; +#define MAX_SPECIFIER_SIZE 4
Could you comment this in detail? other people may be confused this macro.
/*
- success: return IRQ number (>=0)
- failure: return < 0
@@ -255,11 +256,31 @@ int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity) { unsigned int irq; unsigned int plat_gsi = gsi;
- u32 specifier[MAX_SPECIFIER_SIZE];
- plat_gsi = (*__acpi_register_gsi)(dev, gsi, trigger, polarity);
- irq = gsi_to_irq(plat_gsi);
- memset(specifier, 0, sizeof(specifier));
- if (gsi <= 32) {
/* PPI interrupt */
specifier[0] = 1;
- }
- specifier[1] = gsi;
- if (trigger == ACPI_EDGE_SENSITIVE &&
polarity == ACPI_ACTIVE_LOW)
specifier[2] = IRQ_TYPE_EDGE_FALLING;
- else if (trigger == ACPI_EDGE_SENSITIVE &&
polarity == ACPI_ACTIVE_HIGH)
specifier[2] = IRQ_TYPE_EDGE_RISING;
- else if (trigger == ACPI_LEVEL_SENSITIVE &&
polarity == ACPI_ACTIVE_LOW)
specifier[2] = IRQ_TYPE_LEVEL_LOW;
- else if (trigger == ACPI_LEVEL_SENSITIVE &&
polarity == ACPI_ACTIVE_HIGH)
specifier[2] = IRQ_TYPE_LEVEL_HIGH;
- else
specifier[2] = IRQ_TYPE_NONE;
- irq = irq_create_default_mapping(specifier, 3); return irq;
} EXPORT_SYMBOL_GPL(acpi_register_gsi);
Hi Hanjun,
Thanks for the review comments.
On Sat, Oct 12, 2013 at 2:28 PM, Hanjun Guo hanjun.guo@linaro.org wrote:
On 2013-10-9 19:47, Amit Daniel Kachhap wrote:
This API is similar to DT based irq_of_parse_and_map but does link parent/child IRQ controllers. This is tested for primary GIC PPI and GIC SPI interrupts and not for secondary child irq controllers.
Signed-off-by: Amit Daniel Kachhap amit.daniel@samsung.com
drivers/acpi/plat/arm/boot.c | 27 ++++++++++++++++++++++++--- 1 files changed, 24 insertions(+), 3 deletions(-)
diff --git a/drivers/acpi/plat/arm/boot.c b/drivers/acpi/plat/arm/boot.c index 4fcdd9f..53937d8 100644 --- a/drivers/acpi/plat/arm/boot.c +++ b/drivers/acpi/plat/arm/boot.c @@ -247,6 +247,7 @@ static int acpi_register_gsi_ioapic(struct device *dev, u32 gsi, int (*__acpi_register_gsi)(struct device *dev, u32 gsi, int trigger, int polarity) = acpi_register_gsi_pic;
+#define MAX_SPECIFIER_SIZE 4
Could you comment this in detail? other people may be confused this macro.
yes i missed explaining them. Basically 3 parameters are passed to irq_create_mapping API. They are int type, interrupt id and interrupt flag.
/*
- success: return IRQ number (>=0)
- failure: return < 0
@@ -255,11 +256,31 @@ int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity) { unsigned int irq; unsigned int plat_gsi = gsi;
u32 specifier[MAX_SPECIFIER_SIZE];
plat_gsi = (*__acpi_register_gsi)(dev, gsi, trigger, polarity);
irq = gsi_to_irq(plat_gsi);
memset(specifier, 0, sizeof(specifier));
if (gsi <= 32) {
/* PPI interrupt */
specifier[0] = 1;
}
specifier[1] = gsi;
if (trigger == ACPI_EDGE_SENSITIVE &&
polarity == ACPI_ACTIVE_LOW)
specifier[2] = IRQ_TYPE_EDGE_FALLING;
else if (trigger == ACPI_EDGE_SENSITIVE &&
polarity == ACPI_ACTIVE_HIGH)
specifier[2] = IRQ_TYPE_EDGE_RISING;
else if (trigger == ACPI_LEVEL_SENSITIVE &&
polarity == ACPI_ACTIVE_LOW)
specifier[2] = IRQ_TYPE_LEVEL_LOW;
else if (trigger == ACPI_LEVEL_SENSITIVE &&
polarity == ACPI_ACTIVE_HIGH)
specifier[2] = IRQ_TYPE_LEVEL_HIGH;
else
specifier[2] = IRQ_TYPE_NONE;
irq = irq_create_default_mapping(specifier, 3); return irq;
} EXPORT_SYMBOL_GPL(acpi_register_gsi);
Linaro-acpi mailing list Linaro-acpi@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-acpi
On Sat, Oct 12, 2013 at 2:28 PM, Hanjun Guo hanjun.guo@linaro.org wrote:
On 2013-10-9 19:47, Amit Daniel Kachhap wrote:
This API is similar to DT based irq_of_parse_and_map but does link parent/child IRQ controllers. This is tested for primary GIC PPI and GIC SPI interrupts and not for secondary child irq controllers.
Signed-off-by: Amit Daniel Kachhap amit.daniel@samsung.com
drivers/acpi/plat/arm/boot.c | 27 ++++++++++++++++++++++++--- 1 files changed, 24 insertions(+), 3 deletions(-)
diff --git a/drivers/acpi/plat/arm/boot.c b/drivers/acpi/plat/arm/boot.c index 4fcdd9f..53937d8 100644 --- a/drivers/acpi/plat/arm/boot.c +++ b/drivers/acpi/plat/arm/boot.c @@ -247,6 +247,7 @@ static int acpi_register_gsi_ioapic(struct device *dev, u32 gsi, int (*__acpi_register_gsi)(struct device *dev, u32 gsi, int trigger, int polarity) = acpi_register_gsi_pic;
+#define MAX_SPECIFIER_SIZE 4
Could you comment this in detail? other people may be confused this macro.
/*
- success: return IRQ number (>=0)
- failure: return < 0
@@ -255,11 +256,31 @@ int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity) { unsigned int irq; unsigned int plat_gsi = gsi;
u32 specifier[MAX_SPECIFIER_SIZE];
plat_gsi = (*__acpi_register_gsi)(dev, gsi, trigger, polarity);
irq = gsi_to_irq(plat_gsi);
memset(specifier, 0, sizeof(specifier));
if (gsi <= 32) {
/* PPI interrupt */
specifier[0] = 1;
}
specifier[1] = gsi;
if (trigger == ACPI_EDGE_SENSITIVE &&
polarity == ACPI_ACTIVE_LOW)
specifier[2] = IRQ_TYPE_EDGE_FALLING;
else if (trigger == ACPI_EDGE_SENSITIVE &&
polarity == ACPI_ACTIVE_HIGH)
specifier[2] = IRQ_TYPE_EDGE_RISING;
else if (trigger == ACPI_LEVEL_SENSITIVE &&
polarity == ACPI_ACTIVE_LOW)
specifier[2] = IRQ_TYPE_LEVEL_LOW;
else if (trigger == ACPI_LEVEL_SENSITIVE &&
polarity == ACPI_ACTIVE_HIGH)
specifier[2] = IRQ_TYPE_LEVEL_HIGH;
else
specifier[2] = IRQ_TYPE_NONE;
irq = irq_create_default_mapping(specifier, 3); return irq;
} EXPORT_SYMBOL_GPL(acpi_register_gsi);
Linaro-acpi mailing list Linaro-acpi@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-acpi
In case of ACPI dt node is not used so this check is skipped. Also ACPI handle is not initialised at this point so cannot OR the dt check with the ACPI check.
Signed-off-by: Amit Daniel Kachhap amit.daniel@samsung.com --- drivers/irqchip/irq-gic.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 039b4a0..2f18e2f 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -834,8 +834,10 @@ static int gic_irq_domain_xlate(struct irq_domain *d, const u32 *intspec, unsigned int intsize, unsigned long *out_hwirq, unsigned int *out_type) { +#ifndef CONFIG_ACPI if (d->of_node != controller) return -EINVAL; +#endif if (intsize < 3) return -EINVAL;
On 2013-10-9 19:47, Amit Daniel Kachhap wrote:
In case of ACPI dt node is not used so this check is skipped. Also ACPI handle is not initialised at this point so cannot OR the dt check with the ACPI check.
This makes my head hurts too, make the coexist of DT and ACPI is not easy.
Signed-off-by: Amit Daniel Kachhap amit.daniel@samsung.com
drivers/irqchip/irq-gic.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 039b4a0..2f18e2f 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -834,8 +834,10 @@ static int gic_irq_domain_xlate(struct irq_domain *d, const u32 *intspec, unsigned int intsize, unsigned long *out_hwirq, unsigned int *out_type) { +#ifndef CONFIG_ACPI if (d->of_node != controller) return -EINVAL; +#endif
I have a idea, how about introduce a flag (or something else) in struct irq_domain? then we can:
if (d->of_node != controller && d->flag != acpi arch timer is enabled) return -EINVAL;
does it make sense to you?
if (intsize < 3) return -EINVAL;
On Sat, Oct 12, 2013 at 2:56 PM, Hanjun Guo hanjun.guo@linaro.org wrote:
On 2013-10-9 19:47, Amit Daniel Kachhap wrote:
In case of ACPI dt node is not used so this check is skipped. Also ACPI handle is not initialised at this point so cannot OR the dt check with the ACPI check.
This makes my head hurts too, make the coexist of DT and ACPI is not easy.
Signed-off-by: Amit Daniel Kachhap amit.daniel@samsung.com
drivers/irqchip/irq-gic.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 039b4a0..2f18e2f 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -834,8 +834,10 @@ static int gic_irq_domain_xlate(struct irq_domain *d, const u32 *intspec, unsigned int intsize, unsigned long *out_hwirq, unsigned int *out_type) { +#ifndef CONFIG_ACPI if (d->of_node != controller) return -EINVAL; +#endif
I have a idea, how about introduce a flag (or something else) in struct irq_domain? then we can:
if (d->of_node != controller && d->flag != acpi arch timer is enabled) return -EINVAL;
does it make sense to you?
Something like this seems fine. Will do it in the next iteration.
if (intsize < 3) return -EINVAL;
Linaro-acpi mailing list Linaro-acpi@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-acpi
The GTDT table is updated to make the timer table more generic and represent external timers. The field added are to support upto 8 interrupt support in the timer block. frequency and interrupt count parameter is also added. However some more parameter has to added here in future like, 1) Timer clock name. 2) More than 8 interrupt support.
This change also needs corresponding change in acpia tools as shown below,
diff source/common/dmtbinfo.c.org source/common/dmtbinfo.c 992a993
{ACPI_DMT_FLAG1, ACPI_GTDT_FLAG_OFFSET (Flags,0), "Timer Core", 0},
993a995,997
{ACPI_DMT_NAME8, ACPI_GTDT_OFFSET (id[0]), "Timer ID", 0}, {ACPI_DMT_UINT32, ACPI_GTDT_OFFSET (freq), "Timer frequency", 0}, {ACPI_DMT_UINT32, ACPI_GTDT_OFFSET (interrupt_count), "Interrupt count", 0},
1012a1017,1021
ACPI_DMT_NEW_LINE, {ACPI_DMT_UINT64, ACPI_GTDT_OFFSET (reserved5), "reserved5", 0}, {ACPI_DMT_UINT64, ACPI_GTDT_OFFSET (reserved6), "reserved6", 0}, {ACPI_DMT_UINT64, ACPI_GTDT_OFFSET (reserved7), "reserved7", 0}, {ACPI_DMT_UINT64, ACPI_GTDT_OFFSET (reserved8), "reserved8", 0},
Signed-off-by: Amit Daniel Kachhap amit.daniel@samsung.com --- include/acpi/actbl3.h | 22 ++++++++++++++++++++++ 1 files changed, 22 insertions(+), 0 deletions(-)
diff --git a/include/acpi/actbl3.h b/include/acpi/actbl3.h index e2c0931..2525b44 100644 --- a/include/acpi/actbl3.h +++ b/include/acpi/actbl3.h @@ -243,13 +243,18 @@ struct acpi_s3pt_suspend { * * GTDT - Generic Timer Description Table (ACPI 5.0) * Version 1 + * Each timer can support a maximum of 8 interrupts * ******************************************************************************/
struct acpi_table_gtdt { struct acpi_table_header header; /* Common ACPI table header */ u64 address; + u32 size; u32 flags; + u8 id[8]; + u32 freq; + u32 interrupt_count; u32 secure_pl1_interrupt; u32 secure_pl1_flags; u32 non_secure_pl1_interrupt; @@ -258,11 +263,28 @@ struct acpi_table_gtdt { u32 virtual_timer_flags; u32 non_secure_pl2_interrupt; u32 non_secure_pl2_flags; + u64 reserved5; + u64 reserved6; + u64 reserved7; + u64 reserved8; +}; + +struct acpi_table_tdt { + struct acpi_table_header header; /* Common ACPI table header */ + u64 address; + u32 size; + u32 flags; + u8 id[8]; + u32 freq; + u32 interrupt_count; + u32 interrupt_num[8]; + u32 interrupt_flags[8]; };
/* Values for Flags field above */
#define ACPI_GTDT_MAPPED_BLOCK_PRESENT 1 +#define ACPI_GTDT_CORE 2
/* Values for all "TimerFlags" fields above */
On 2013-10-9 19:47, Amit Daniel Kachhap wrote:
The GTDT table is updated to make the timer table more generic and represent external timers. The field added are to support upto 8 interrupt support in the timer block. frequency and interrupt count parameter is also added. However some more parameter has to added here in future like,
- Timer clock name.
- More than 8 interrupt support.
This change also needs corresponding change in acpia tools as shown below,
Great, we need this patch too :)
On Sat, Oct 12, 2013 at 2:57 PM, Hanjun Guo hanjun.guo@linaro.org wrote:
On 2013-10-9 19:47, Amit Daniel Kachhap wrote:
The GTDT table is updated to make the timer table more generic and represent external timers. The field added are to support upto 8 interrupt support in the timer block. frequency and interrupt count parameter is also added. However some more parameter has to added here in future like,
- Timer clock name.
- More than 8 interrupt support.
This change also needs corresponding change in acpia tools as shown below,
Great, we need this patch too :)
yes I was not sure whether to post this patch so just added the diff.
Linaro-acpi mailing list Linaro-acpi@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-acpi
This macro does the same job as CLOCKSOURCE_OF_DECLARE. The device name from the ACPI timer table is matched with all the registered timer controllers and matching initialisation routine is invoked.
Signed-off-by: Amit Daniel Kachhap amit.daniel@samsung.com --- include/asm-generic/vmlinux.lds.h | 6 ++++++ include/linux/clocksource.h | 13 +++++++++++++ 2 files changed, 19 insertions(+), 0 deletions(-)
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 83e2c31..e015ca2 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -144,8 +144,13 @@ VMLINUX_SYMBOL(__clksrc_of_table) = .; \ *(__clksrc_of_table) \ *(__clksrc_of_table_end) +#define CLKSRC_ACPI_TABLES() . = ALIGN(8); \ + VMLINUX_SYMBOL(__clksrc_acpi_table) = .; \ + *(__clksrc_acpi_table) \ + *(__clksrc_acpi_table_end) #else #define CLKSRC_OF_TABLES() +#define CLKSRC_ACPI_TABLES() #endif
#ifdef CONFIG_IRQCHIP @@ -490,6 +495,7 @@ MEM_DISCARD(init.rodata) \ CLK_OF_TABLES() \ CLKSRC_OF_TABLES() \ + CLKSRC_ACPI_TABLES() \ KERNEL_DTB() \ IRQCHIP_OF_MATCH_TABLE()
diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h index dbbf8aa..c300d50 100644 --- a/include/linux/clocksource.h +++ b/include/linux/clocksource.h @@ -338,7 +338,10 @@ extern int clocksource_mmio_init(void __iomem *, const char *, extern int clocksource_i8253_init(void);
struct device_node; + typedef void(*clocksource_of_init_fn)(struct device_node *); +typedef void(*clocksource_acpi_init_fn)(void); + #ifdef CONFIG_CLKSRC_OF extern void clocksource_of_init(void);
@@ -356,4 +359,14 @@ static inline void clocksource_of_init(void) {} .data = (fn == (clocksource_of_init_fn)NULL) ? fn : fn } #endif
+#ifdef CONFIG_ACPI +#define CLOCKSOURCE_ACPI_DECLARE(name, compat, fn) \ + static const struct acpi_device_id __clksrc_acpi_table_##name \ + __used __section(__clksrc_acpi_table) \ + = { .id = compat, \ + .driver_data = (kernel_ulong_t)fn } +#else +#define CLOCKSOURCE_ACPI_DECLARE(name, compat, fn) +#endif + #endif /* _LINUX_CLOCKSOURCE_H */
On 2013-10-9 19:47, Amit Daniel Kachhap wrote:
This macro does the same job as CLOCKSOURCE_OF_DECLARE. The device name from the ACPI timer table is matched with all the registered timer controllers and matching initialisation routine is invoked.
Oh, this approach is really creative and interesting, I will read more about it :)
Signed-off-by: Amit Daniel Kachhap amit.daniel@samsung.com
include/asm-generic/vmlinux.lds.h | 6 ++++++ include/linux/clocksource.h | 13 +++++++++++++ 2 files changed, 19 insertions(+), 0 deletions(-)
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 83e2c31..e015ca2 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -144,8 +144,13 @@ VMLINUX_SYMBOL(__clksrc_of_table) = .; \ *(__clksrc_of_table) \ *(__clksrc_of_table_end) +#define CLKSRC_ACPI_TABLES() . = ALIGN(8); \
VMLINUX_SYMBOL(__clksrc_acpi_table) = .; \
*(__clksrc_acpi_table) \
*(__clksrc_acpi_table_end)
#else #define CLKSRC_OF_TABLES() +#define CLKSRC_ACPI_TABLES() #endif #ifdef CONFIG_IRQCHIP @@ -490,6 +495,7 @@ MEM_DISCARD(init.rodata) \ CLK_OF_TABLES() \ CLKSRC_OF_TABLES() \
- CLKSRC_ACPI_TABLES() \ KERNEL_DTB() \ IRQCHIP_OF_MATCH_TABLE()
diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h index dbbf8aa..c300d50 100644 --- a/include/linux/clocksource.h +++ b/include/linux/clocksource.h @@ -338,7 +338,10 @@ extern int clocksource_mmio_init(void __iomem *, const char *, extern int clocksource_i8253_init(void); struct device_node;
typedef void(*clocksource_of_init_fn)(struct device_node *); +typedef void(*clocksource_acpi_init_fn)(void);
#ifdef CONFIG_CLKSRC_OF extern void clocksource_of_init(void); @@ -356,4 +359,14 @@ static inline void clocksource_of_init(void) {} .data = (fn == (clocksource_of_init_fn)NULL) ? fn : fn } #endif +#ifdef CONFIG_ACPI +#define CLOCKSOURCE_ACPI_DECLARE(name, compat, fn) \
- static const struct acpi_device_id __clksrc_acpi_table_##name \
__used __section(__clksrc_acpi_table) \
= { .id = compat, \
.driver_data = (kernel_ulong_t)fn }
+#else +#define CLOCKSOURCE_ACPI_DECLARE(name, compat, fn) +#endif
#endif /* _LINUX_CLOCKSOURCE_H */
This code changes uses GTDT ACPI table to gather IRQ number, frequency etc. Arm timer is registered with the ACPI timer table. GTDT table device name is matched with all the registered timers and matching initialisation function is called.
Signed-off-by: Amit Daniel Kachhap amit.daniel@samsung.com --- drivers/clocksource/arm_arch_timer.c | 111 +++++++++++++++++++++++++++++----- drivers/clocksource/clksrc-of.c | 32 ++++++++++ 2 files changed, 128 insertions(+), 15 deletions(-)
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index fbd9ccd..8b747f4 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -25,6 +25,10 @@
#include <clocksource/arm_arch_timer.h>
+#ifdef CONFIG_ACPI +#include <linux/acpi.h> +#endif + #define CNTTIDR 0x08 #define CNTTIDR_VIRT(n) (BIT(1) << ((n) * 4))
@@ -579,20 +583,8 @@ static void __init arch_timer_common_init(void) arch_timer_arch_init(); }
-static void __init arch_timer_init(struct device_node *np) +static void __init arch_timer_init(void) { - int i; - - if (arch_timers_present & ARCH_CP15_TIMER) { - pr_warn("arch_timer: multiple nodes in dt, skipping\n"); - return; - } - - arch_timers_present |= ARCH_CP15_TIMER; - for (i = PHYS_SECURE_PPI; i < MAX_TIMER_PPI; i++) - arch_timer_ppi[i] = irq_of_parse_and_map(np, i); - arch_timer_detect_rate(NULL, np); - /* * If HYP mode is available, we know that the physical timer * has been configured to be accessible from PL1. Use it, so @@ -614,8 +606,97 @@ static void __init arch_timer_init(struct device_node *np) arch_timer_register(); arch_timer_common_init(); } -CLOCKSOURCE_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer", arch_timer_init); -CLOCKSOURCE_OF_DECLARE(armv8_arch_timer, "arm,armv8-timer", arch_timer_init); + +static void __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"); + return; + } + + arch_timers_present |= ARCH_CP15_TIMER; + for (i = PHYS_SECURE_PPI; i < MAX_TIMER_PPI; i++) + arch_timer_ppi[i] = irq_of_parse_and_map(np, i); + arch_timer_detect_rate(NULL, np); + + arch_timer_init(); +} + +#ifdef CONFIG_ACPI +static void __init arch_timer_acpi_init(void) +{ + struct acpi_table_gtdt *gtdt; + int trigger, polarity; + + if (arch_timers_present & ARCH_CP15_TIMER) { + pr_warn("arch_timer: multiple nodes in dt, skipping\n"); + return; + } + arch_timers_present |= ARCH_CP15_TIMER; + + if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_GTDT, 0, + (struct acpi_table_header **)>dt))) { + pr_err("arch_timer: GTDT table not defined\n"); + return; + } + /* Read the GTDT table to get the frequency */ + if (gtdt->freq) + arch_timer_rate = gtdt->freq; + else + arch_timer_rate = arch_timer_get_cntfrq(); + + if (gtdt->secure_pl1_interrupt) { + trigger = (gtdt->secure_pl1_flags & ACPI_GTDT_INTERRUPT_MODE) ? + ACPI_EDGE_SENSITIVE : ACPI_LEVEL_SENSITIVE; + polarity = + (gtdt->secure_pl1_flags & ACPI_GTDT_INTERRUPT_POLARITY) + ? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH; + arch_timer_ppi[0] = acpi_register_gsi(NULL, + gtdt->secure_pl1_interrupt, trigger, polarity); + } + if (gtdt->non_secure_pl1_interrupt) { + trigger = + (gtdt->non_secure_pl1_flags & ACPI_GTDT_INTERRUPT_MODE) + ? ACPI_EDGE_SENSITIVE : ACPI_LEVEL_SENSITIVE; + polarity = + (gtdt->non_secure_pl1_flags & ACPI_GTDT_INTERRUPT_POLARITY) + ? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH; + arch_timer_ppi[1] = acpi_register_gsi(NULL, + gtdt->non_secure_pl1_interrupt, trigger, polarity); + } + if (gtdt->virtual_timer_interrupt) { + trigger = (gtdt->virtual_timer_flags & ACPI_GTDT_INTERRUPT_MODE) + ? ACPI_EDGE_SENSITIVE : ACPI_LEVEL_SENSITIVE; + polarity = + (gtdt->virtual_timer_flags & ACPI_GTDT_INTERRUPT_POLARITY) + ? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH; + arch_timer_ppi[2] = acpi_register_gsi(NULL, + gtdt->virtual_timer_interrupt, trigger, polarity); + } + if (gtdt->non_secure_pl2_interrupt) { + trigger = + (gtdt->non_secure_pl2_flags & ACPI_GTDT_INTERRUPT_MODE) + ? ACPI_EDGE_SENSITIVE : ACPI_LEVEL_SENSITIVE; + polarity = + (gtdt->non_secure_pl2_flags & ACPI_GTDT_INTERRUPT_POLARITY) + ? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH; + arch_timer_ppi[3] = acpi_register_gsi(NULL, + gtdt->non_secure_pl2_interrupt, trigger, polarity); + } + + arch_timer_init(); +} +#else +#define arch_timer_acpi_init NULL +#endif + + +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); +CLOCKSOURCE_ACPI_DECLARE(armv7_arch_timer, "ARMV7", arch_timer_acpi_init); +CLOCKSOURCE_ACPI_DECLARE(armv8_arch_timer, "ARMV8", arch_timer_acpi_init);
static void __init arch_timer_mem_init(struct device_node *np) { diff --git a/drivers/clocksource/clksrc-of.c b/drivers/clocksource/clksrc-of.c index 37f5325..8d70903 100644 --- a/drivers/clocksource/clksrc-of.c +++ b/drivers/clocksource/clksrc-of.c @@ -17,12 +17,23 @@ #include <linux/init.h> #include <linux/of.h> #include <linux/clocksource.h> +#ifdef CONFIG_ACPI +#include <linux/acpi.h> +#endif
extern struct of_device_id __clksrc_of_table[];
static const struct of_device_id __clksrc_of_table_sentinel __used __section(__clksrc_of_table_end);
+#if CONFIG_ACPI +extern struct acpi_device_id __clksrc_acpi_table[]; + +static const struct acpi_device_id __clksrc_acpi_table_sentinel + __used __section(__clksrc_acpi_table_end); + +#endif + void __init clocksource_of_init(void) { struct device_node *np; @@ -33,4 +44,25 @@ void __init clocksource_of_init(void) init_func = match->data; init_func(np); } +#if CONFIG_ACPI + /* This code section uses the GTDT table TIMER + * id to match the correct clock source device */ + struct acpi_table_gtdt *tdt; + const struct acpi_device_id *id; + clocksource_acpi_init_fn acpi_init_func; + + if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_GTDT, 0, + (struct acpi_table_header **)&tdt))) { + return; + } + + for (id = __clksrc_acpi_table; id->id[0]; id++) { + if (!strncmp((char *) id->id, tdt->id, strlen(id->id))) { + acpi_init_func = + (clocksource_acpi_init_fn)id->driver_data; + acpi_init_func(); + break; + } + } +#endif }
On 2013年10月09日 19:47, Amit Daniel Kachhap wrote:
This code changes uses GTDT ACPI table to gather IRQ number, frequency etc. Arm timer is registered with the ACPI timer table. GTDT table device name is matched with all the registered timers and matching initialisation function is called.
Signed-off-by: Amit Daniel Kachhap amit.daniel@samsung.com
drivers/clocksource/arm_arch_timer.c | 111 +++++++++++++++++++++++++++++----- drivers/clocksource/clksrc-of.c | 32 ++++++++++ 2 files changed, 128 insertions(+), 15 deletions(-)
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index fbd9ccd..8b747f4 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -25,6 +25,10 @@ #include <clocksource/arm_arch_timer.h> +#ifdef CONFIG_ACPI +#include <linux/acpi.h> +#endif
- #define CNTTIDR 0x08 #define CNTTIDR_VIRT(n) (BIT(1) << ((n) * 4))
@@ -579,20 +583,8 @@ static void __init arch_timer_common_init(void) arch_timer_arch_init(); } -static void __init arch_timer_init(struct device_node *np) +static void __init arch_timer_init(void) {
- int i;
- if (arch_timers_present & ARCH_CP15_TIMER) {
pr_warn("arch_timer: multiple nodes in dt, skipping\n");
return;
- }
- arch_timers_present |= ARCH_CP15_TIMER;
- for (i = PHYS_SECURE_PPI; i < MAX_TIMER_PPI; i++)
arch_timer_ppi[i] = irq_of_parse_and_map(np, i);
- arch_timer_detect_rate(NULL, np);
- /*
- If HYP mode is available, we know that the physical timer
- has been configured to be accessible from PL1. Use it, so
@@ -614,8 +606,97 @@ static void __init arch_timer_init(struct device_node *np) arch_timer_register(); arch_timer_common_init(); } -CLOCKSOURCE_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer", arch_timer_init); -CLOCKSOURCE_OF_DECLARE(armv8_arch_timer, "arm,armv8-timer", arch_timer_init);
+static void __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");
return;
- }
- arch_timers_present |= ARCH_CP15_TIMER;
- for (i = PHYS_SECURE_PPI; i < MAX_TIMER_PPI; i++)
arch_timer_ppi[i] = irq_of_parse_and_map(np, i);
- arch_timer_detect_rate(NULL, np);
- arch_timer_init();
+}
+#ifdef CONFIG_ACPI +static void __init arch_timer_acpi_init(void) +{
- struct acpi_table_gtdt *gtdt;
- int trigger, polarity;
- if (arch_timers_present & ARCH_CP15_TIMER) {
pr_warn("arch_timer: multiple nodes in dt, skipping\n");
return;
- }
- arch_timers_present |= ARCH_CP15_TIMER;
- if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_GTDT, 0,
(struct acpi_table_header **)>dt))) {
pr_err("arch_timer: GTDT table not defined\n");
return;
- }
- /* Read the GTDT table to get the frequency */
- if (gtdt->freq)
arch_timer_rate = gtdt->freq;
- else
arch_timer_rate = arch_timer_get_cntfrq();
- if (gtdt->secure_pl1_interrupt) {
trigger = (gtdt->secure_pl1_flags & ACPI_GTDT_INTERRUPT_MODE) ?
ACPI_EDGE_SENSITIVE : ACPI_LEVEL_SENSITIVE;
polarity =
(gtdt->secure_pl1_flags & ACPI_GTDT_INTERRUPT_POLARITY)
? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH;
arch_timer_ppi[0] = acpi_register_gsi(NULL,
gtdt->secure_pl1_interrupt, trigger, polarity);
- }
- if (gtdt->non_secure_pl1_interrupt) {
trigger =
(gtdt->non_secure_pl1_flags & ACPI_GTDT_INTERRUPT_MODE)
? ACPI_EDGE_SENSITIVE : ACPI_LEVEL_SENSITIVE;
polarity =
(gtdt->non_secure_pl1_flags & ACPI_GTDT_INTERRUPT_POLARITY)
? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH;
arch_timer_ppi[1] = acpi_register_gsi(NULL,
gtdt->non_secure_pl1_interrupt, trigger, polarity);
- }
- if (gtdt->virtual_timer_interrupt) {
trigger = (gtdt->virtual_timer_flags & ACPI_GTDT_INTERRUPT_MODE)
? ACPI_EDGE_SENSITIVE : ACPI_LEVEL_SENSITIVE;
polarity =
(gtdt->virtual_timer_flags & ACPI_GTDT_INTERRUPT_POLARITY)
? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH;
arch_timer_ppi[2] = acpi_register_gsi(NULL,
gtdt->virtual_timer_interrupt, trigger, polarity);
- }
- if (gtdt->non_secure_pl2_interrupt) {
trigger =
(gtdt->non_secure_pl2_flags & ACPI_GTDT_INTERRUPT_MODE)
? ACPI_EDGE_SENSITIVE : ACPI_LEVEL_SENSITIVE;
polarity =
(gtdt->non_secure_pl2_flags & ACPI_GTDT_INTERRUPT_POLARITY)
? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH;
arch_timer_ppi[3] = acpi_register_gsi(NULL,
gtdt->non_secure_pl2_interrupt, trigger, polarity);
- }
- arch_timer_init();
+} +#else +#define arch_timer_acpi_init NULL +#endif
+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); +CLOCKSOURCE_ACPI_DECLARE(armv7_arch_timer, "ARMV7", arch_timer_acpi_init); +CLOCKSOURCE_ACPI_DECLARE(armv8_arch_timer, "ARMV8", arch_timer_acpi_init); static void __init arch_timer_mem_init(struct device_node *np) { diff --git a/drivers/clocksource/clksrc-of.c b/drivers/clocksource/clksrc-of.c index 37f5325..8d70903 100644 --- a/drivers/clocksource/clksrc-of.c +++ b/drivers/clocksource/clksrc-of.c @@ -17,12 +17,23 @@ #include <linux/init.h> #include <linux/of.h> #include <linux/clocksource.h> +#ifdef CONFIG_ACPI +#include <linux/acpi.h> +#endif extern struct of_device_id __clksrc_of_table[]; static const struct of_device_id __clksrc_of_table_sentinel __used __section(__clksrc_of_table_end); +#if CONFIG_ACPI +extern struct acpi_device_id __clksrc_acpi_table[];
+static const struct acpi_device_id __clksrc_acpi_table_sentinel
- __used __section(__clksrc_acpi_table_end);
+#endif
- void __init clocksource_of_init(void) { struct device_node *np;
@@ -33,4 +44,25 @@ void __init clocksource_of_init(void) init_func = match->data; init_func(np); } +#if CONFIG_ACPI
- /* This code section uses the GTDT table TIMER
* id to match the correct clock source device */
- struct acpi_table_gtdt *tdt;
- const struct acpi_device_id *id;
- clocksource_acpi_init_fn acpi_init_func;
- if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_GTDT, 0,
(struct acpi_table_header **)&tdt))) {
return;
- }
- for (id = __clksrc_acpi_table; id->id[0]; id++) {
if (!strncmp((char *) id->id, tdt->id, strlen(id->id))) {
acpi_init_func =
(clocksource_acpi_init_fn)id->driver_data;
acpi_init_func();
break;
}
- }
+#endif
This function is *clocksource_of_init*, can we introduce a new function for ACPI only?
Thanks Hanjun
}
On Sat, Oct 12, 2013 at 8:07 PM, Hanjun Guo hanjun.guo@linaro.org wrote:
On 2013年10月09日 19:47, Amit Daniel Kachhap wrote:
This code changes uses GTDT ACPI table to gather IRQ number, frequency etc. Arm timer is registered with the ACPI timer table. GTDT table device name is matched with all the registered timers and matching initialisation function is called.
Signed-off-by: Amit Daniel Kachhap amit.daniel@samsung.com
drivers/clocksource/arm_arch_timer.c | 111 +++++++++++++++++++++++++++++----- drivers/clocksource/clksrc-of.c | 32 ++++++++++ 2 files changed, 128 insertions(+), 15 deletions(-)
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index fbd9ccd..8b747f4 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -25,6 +25,10 @@ #include <clocksource/arm_arch_timer.h> +#ifdef CONFIG_ACPI +#include <linux/acpi.h> +#endif
- #define CNTTIDR 0x08 #define CNTTIDR_VIRT(n) (BIT(1) << ((n) * 4)) @@ -579,20 +583,8 @@ static void __init arch_timer_common_init(void) arch_timer_arch_init(); } -static void __init arch_timer_init(struct device_node *np)
+static void __init arch_timer_init(void) {
int i;
if (arch_timers_present & ARCH_CP15_TIMER) {
pr_warn("arch_timer: multiple nodes in dt, skipping\n");
return;
}
arch_timers_present |= ARCH_CP15_TIMER;
for (i = PHYS_SECURE_PPI; i < MAX_TIMER_PPI; i++)
arch_timer_ppi[i] = irq_of_parse_and_map(np, i);
arch_timer_detect_rate(NULL, np);
/* * If HYP mode is available, we know that the physical timer * has been configured to be accessible from PL1. Use it, so
@@ -614,8 +606,97 @@ static void __init arch_timer_init(struct device_node *np) arch_timer_register(); arch_timer_common_init(); } -CLOCKSOURCE_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer", arch_timer_init); -CLOCKSOURCE_OF_DECLARE(armv8_arch_timer, "arm,armv8-timer", arch_timer_init);
+static void __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");
return;
}
arch_timers_present |= ARCH_CP15_TIMER;
for (i = PHYS_SECURE_PPI; i < MAX_TIMER_PPI; i++)
arch_timer_ppi[i] = irq_of_parse_and_map(np, i);
arch_timer_detect_rate(NULL, np);
arch_timer_init();
+}
+#ifdef CONFIG_ACPI +static void __init arch_timer_acpi_init(void) +{
struct acpi_table_gtdt *gtdt;
int trigger, polarity;
if (arch_timers_present & ARCH_CP15_TIMER) {
pr_warn("arch_timer: multiple nodes in dt, skipping\n");
return;
}
arch_timers_present |= ARCH_CP15_TIMER;
if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_GTDT, 0,
(struct acpi_table_header **)>dt))) {
pr_err("arch_timer: GTDT table not defined\n");
return;
}
/* Read the GTDT table to get the frequency */
if (gtdt->freq)
arch_timer_rate = gtdt->freq;
else
arch_timer_rate = arch_timer_get_cntfrq();
if (gtdt->secure_pl1_interrupt) {
trigger = (gtdt->secure_pl1_flags &
ACPI_GTDT_INTERRUPT_MODE) ?
ACPI_EDGE_SENSITIVE : ACPI_LEVEL_SENSITIVE;
polarity =
(gtdt->secure_pl1_flags &
ACPI_GTDT_INTERRUPT_POLARITY)
? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH;
arch_timer_ppi[0] = acpi_register_gsi(NULL,
gtdt->secure_pl1_interrupt, trigger,
polarity);
}
if (gtdt->non_secure_pl1_interrupt) {
trigger =
(gtdt->non_secure_pl1_flags &
ACPI_GTDT_INTERRUPT_MODE)
? ACPI_EDGE_SENSITIVE : ACPI_LEVEL_SENSITIVE;
polarity =
(gtdt->non_secure_pl1_flags &
ACPI_GTDT_INTERRUPT_POLARITY)
? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH;
arch_timer_ppi[1] = acpi_register_gsi(NULL,
gtdt->non_secure_pl1_interrupt, trigger,
polarity);
}
if (gtdt->virtual_timer_interrupt) {
trigger = (gtdt->virtual_timer_flags &
ACPI_GTDT_INTERRUPT_MODE)
? ACPI_EDGE_SENSITIVE : ACPI_LEVEL_SENSITIVE;
polarity =
(gtdt->virtual_timer_flags & ACPI_GTDT_INTERRUPT_POLARITY)
? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH;
arch_timer_ppi[2] = acpi_register_gsi(NULL,
gtdt->virtual_timer_interrupt, trigger, polarity);
}
if (gtdt->non_secure_pl2_interrupt) {
trigger =
(gtdt->non_secure_pl2_flags &
ACPI_GTDT_INTERRUPT_MODE)
? ACPI_EDGE_SENSITIVE : ACPI_LEVEL_SENSITIVE;
polarity =
(gtdt->non_secure_pl2_flags &
ACPI_GTDT_INTERRUPT_POLARITY)
? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH;
arch_timer_ppi[3] = acpi_register_gsi(NULL,
gtdt->non_secure_pl2_interrupt, trigger,
polarity);
}
arch_timer_init();
+} +#else +#define arch_timer_acpi_init NULL +#endif
+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); +CLOCKSOURCE_ACPI_DECLARE(armv7_arch_timer, "ARMV7", arch_timer_acpi_init); +CLOCKSOURCE_ACPI_DECLARE(armv8_arch_timer, "ARMV8", arch_timer_acpi_init); static void __init arch_timer_mem_init(struct device_node *np) { diff --git a/drivers/clocksource/clksrc-of.c b/drivers/clocksource/clksrc-of.c index 37f5325..8d70903 100644 --- a/drivers/clocksource/clksrc-of.c +++ b/drivers/clocksource/clksrc-of.c @@ -17,12 +17,23 @@ #include <linux/init.h> #include <linux/of.h> #include <linux/clocksource.h> +#ifdef CONFIG_ACPI +#include <linux/acpi.h> +#endif extern struct of_device_id __clksrc_of_table[]; static const struct of_device_id __clksrc_of_table_sentinel __used __section(__clksrc_of_table_end); +#if CONFIG_ACPI +extern struct acpi_device_id __clksrc_acpi_table[];
+static const struct acpi_device_id __clksrc_acpi_table_sentinel
__used __section(__clksrc_acpi_table_end);
+#endif
- void __init clocksource_of_init(void) { struct device_node *np;
@@ -33,4 +44,25 @@ void __init clocksource_of_init(void) init_func = match->data; init_func(np); } +#if CONFIG_ACPI
/* This code section uses the GTDT table TIMER
* id to match the correct clock source device */
struct acpi_table_gtdt *tdt;
const struct acpi_device_id *id;
clocksource_acpi_init_fn acpi_init_func;
if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_GTDT, 0,
(struct acpi_table_header **)&tdt))) {
return;
}
for (id = __clksrc_acpi_table; id->id[0]; id++) {
if (!strncmp((char *) id->id, tdt->id, strlen(id->id))) {
acpi_init_func =
(clocksource_acpi_init_fn)id->driver_data;
acpi_init_func();
break;
}
}
+#endif
This function is *clocksource_of_init*, can we introduce a new function for ACPI only?
Right this function can renamed to something generic.
Thanks Hanjun
}
Linaro-acpi mailing list Linaro-acpi@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-acpi
On Sat, Oct 12, 2013 at 8:07 PM, Hanjun Guo hanjun.guo@linaro.org wrote:
On 2013年10月09日 19:47, Amit Daniel Kachhap wrote:
This code changes uses GTDT ACPI table to gather IRQ number, frequency etc. Arm timer is registered with the ACPI timer table. GTDT table device name is matched with all the registered timers and matching initialisation function is called.
Signed-off-by: Amit Daniel Kachhap amit.daniel@samsung.com
drivers/clocksource/arm_arch_timer.c | 111 +++++++++++++++++++++++++++++----- drivers/clocksource/clksrc-of.c | 32 ++++++++++ 2 files changed, 128 insertions(+), 15 deletions(-)
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index fbd9ccd..8b747f4 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -25,6 +25,10 @@ #include <clocksource/arm_arch_timer.h> +#ifdef CONFIG_ACPI +#include <linux/acpi.h> +#endif
- #define CNTTIDR 0x08 #define CNTTIDR_VIRT(n) (BIT(1) << ((n) * 4)) @@ -579,20 +583,8 @@ static void __init arch_timer_common_init(void) arch_timer_arch_init(); } -static void __init arch_timer_init(struct device_node *np)
+static void __init arch_timer_init(void) {
int i;
if (arch_timers_present & ARCH_CP15_TIMER) {
pr_warn("arch_timer: multiple nodes in dt, skipping\n");
return;
}
arch_timers_present |= ARCH_CP15_TIMER;
for (i = PHYS_SECURE_PPI; i < MAX_TIMER_PPI; i++)
arch_timer_ppi[i] = irq_of_parse_and_map(np, i);
arch_timer_detect_rate(NULL, np);
/* * If HYP mode is available, we know that the physical timer * has been configured to be accessible from PL1. Use it, so
@@ -614,8 +606,97 @@ static void __init arch_timer_init(struct device_node *np) arch_timer_register(); arch_timer_common_init(); } -CLOCKSOURCE_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer", arch_timer_init); -CLOCKSOURCE_OF_DECLARE(armv8_arch_timer, "arm,armv8-timer", arch_timer_init);
+static void __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");
return;
}
arch_timers_present |= ARCH_CP15_TIMER;
for (i = PHYS_SECURE_PPI; i < MAX_TIMER_PPI; i++)
arch_timer_ppi[i] = irq_of_parse_and_map(np, i);
arch_timer_detect_rate(NULL, np);
arch_timer_init();
+}
+#ifdef CONFIG_ACPI +static void __init arch_timer_acpi_init(void) +{
struct acpi_table_gtdt *gtdt;
int trigger, polarity;
if (arch_timers_present & ARCH_CP15_TIMER) {
pr_warn("arch_timer: multiple nodes in dt, skipping\n");
return;
}
arch_timers_present |= ARCH_CP15_TIMER;
if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_GTDT, 0,
(struct acpi_table_header **)>dt))) {
pr_err("arch_timer: GTDT table not defined\n");
return;
}
/* Read the GTDT table to get the frequency */
if (gtdt->freq)
arch_timer_rate = gtdt->freq;
else
arch_timer_rate = arch_timer_get_cntfrq();
if (gtdt->secure_pl1_interrupt) {
trigger = (gtdt->secure_pl1_flags &
ACPI_GTDT_INTERRUPT_MODE) ?
ACPI_EDGE_SENSITIVE : ACPI_LEVEL_SENSITIVE;
polarity =
(gtdt->secure_pl1_flags &
ACPI_GTDT_INTERRUPT_POLARITY)
? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH;
arch_timer_ppi[0] = acpi_register_gsi(NULL,
gtdt->secure_pl1_interrupt, trigger,
polarity);
}
if (gtdt->non_secure_pl1_interrupt) {
trigger =
(gtdt->non_secure_pl1_flags &
ACPI_GTDT_INTERRUPT_MODE)
? ACPI_EDGE_SENSITIVE : ACPI_LEVEL_SENSITIVE;
polarity =
(gtdt->non_secure_pl1_flags &
ACPI_GTDT_INTERRUPT_POLARITY)
? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH;
arch_timer_ppi[1] = acpi_register_gsi(NULL,
gtdt->non_secure_pl1_interrupt, trigger,
polarity);
}
if (gtdt->virtual_timer_interrupt) {
trigger = (gtdt->virtual_timer_flags &
ACPI_GTDT_INTERRUPT_MODE)
? ACPI_EDGE_SENSITIVE : ACPI_LEVEL_SENSITIVE;
polarity =
(gtdt->virtual_timer_flags & ACPI_GTDT_INTERRUPT_POLARITY)
? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH;
arch_timer_ppi[2] = acpi_register_gsi(NULL,
gtdt->virtual_timer_interrupt, trigger, polarity);
}
if (gtdt->non_secure_pl2_interrupt) {
trigger =
(gtdt->non_secure_pl2_flags &
ACPI_GTDT_INTERRUPT_MODE)
? ACPI_EDGE_SENSITIVE : ACPI_LEVEL_SENSITIVE;
polarity =
(gtdt->non_secure_pl2_flags &
ACPI_GTDT_INTERRUPT_POLARITY)
? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH;
arch_timer_ppi[3] = acpi_register_gsi(NULL,
gtdt->non_secure_pl2_interrupt, trigger,
polarity);
}
arch_timer_init();
+} +#else +#define arch_timer_acpi_init NULL +#endif
+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); +CLOCKSOURCE_ACPI_DECLARE(armv7_arch_timer, "ARMV7", arch_timer_acpi_init); +CLOCKSOURCE_ACPI_DECLARE(armv8_arch_timer, "ARMV8", arch_timer_acpi_init); static void __init arch_timer_mem_init(struct device_node *np) { diff --git a/drivers/clocksource/clksrc-of.c b/drivers/clocksource/clksrc-of.c index 37f5325..8d70903 100644 --- a/drivers/clocksource/clksrc-of.c +++ b/drivers/clocksource/clksrc-of.c @@ -17,12 +17,23 @@ #include <linux/init.h> #include <linux/of.h> #include <linux/clocksource.h> +#ifdef CONFIG_ACPI +#include <linux/acpi.h> +#endif extern struct of_device_id __clksrc_of_table[]; static const struct of_device_id __clksrc_of_table_sentinel __used __section(__clksrc_of_table_end); +#if CONFIG_ACPI +extern struct acpi_device_id __clksrc_acpi_table[];
+static const struct acpi_device_id __clksrc_acpi_table_sentinel
__used __section(__clksrc_acpi_table_end);
+#endif
- void __init clocksource_of_init(void) { struct device_node *np;
@@ -33,4 +44,25 @@ void __init clocksource_of_init(void) init_func = match->data; init_func(np); } +#if CONFIG_ACPI
/* This code section uses the GTDT table TIMER
* id to match the correct clock source device */
struct acpi_table_gtdt *tdt;
const struct acpi_device_id *id;
clocksource_acpi_init_fn acpi_init_func;
if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_GTDT, 0,
(struct acpi_table_header **)&tdt))) {
return;
}
for (id = __clksrc_acpi_table; id->id[0]; id++) {
if (!strncmp((char *) id->id, tdt->id, strlen(id->id))) {
acpi_init_func =
(clocksource_acpi_init_fn)id->driver_data;
acpi_init_func();
break;
}
}
+#endif
This function is *clocksource_of_init*, can we introduce a new function for ACPI only?
Thanks Hanjun
}
Linaro-acpi mailing list Linaro-acpi@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-acpi
Using exynos5440 for testing the ACPI interrupt mapping/parsing as this platform uses arm internal timer.
Signed-off-by: Amit Daniel Kachhap amit.daniel@samsung.com --- platforms/exynos5440-ssdk5440.acpi/gtdt.asl | 53 +++++++++++++++++++++++++++ 1 files changed, 53 insertions(+), 0 deletions(-) create mode 100644 platforms/exynos5440-ssdk5440.acpi/gtdt.asl
diff --git a/platforms/exynos5440-ssdk5440.acpi/gtdt.asl b/platforms/exynos5440-ssdk5440.acpi/gtdt.asl new file mode 100644 index 0000000..750f4d8 --- /dev/null +++ b/platforms/exynos5440-ssdk5440.acpi/gtdt.asl @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2013, Al Stone al.stone@linaro.org + * + * [GTDT] Generic Timer Description Table + * Format: [ByteLength] FieldName : HexFieldValue + * + * This source is released under the terms of the GPLv2. + */ + +[0004] Signature : "GTDT" +[0004] Table Length : 00000084 +[0001] Revision : 01 +[0001] Checksum : F1 +[0006] Oem ID : "LINARO" +[0008] Oem Table ID : "5440 " +[0004] Oem Revision : 00000001 +[0004] Asl Compiler ID : "INTL" +[0004] Asl Compiler Revision : 20110623 + +[0008] Timer Address : 0000000000000000 +[0004] Timer Size : 00000000 +[0004] Flags (decoded below) : 00000001 + Memory Present : 1 + Timer Core : 1 + +[0008] Timer ID : "ARMV7 " +[0004] Timer frequency : 02faf080 +[0004] Interrupt count : 4 + +[0004] Secure PL1 Interrupt : 0000000d +[0004] SPL1 Flags (decoded below) : 00000000 + Trigger Mode : 0 + Polarity : 1 + +[0004] Non-Secure PL1 Interrupt : 0000000e +[0004] NSPL1 Flags (decoded below) : 00000000 + Trigger Mode : 0 + Polarity : 1 + +[0004] Virtual Timer Interrupt : 0000000b +[0004] VT Flags (decoded below) : 00000000 + Trigger Mode : 0 + Polarity : 1 + +[0004] Non-Secure PL2 Interrupt : 0000000a +[0004] NSPL2 Flags (decoded below) : 00000000 + Trigger Mode : 0 + Polarity : 1 + +[0008] reserved5 : 0000000000000000 +[0008] reserved6 : 0000000000000000 +[0008] reserved7 : 0000000000000000 +[0008] reserved8 : 0000000000000000
On 10/09/2013 05:47 AM, Amit Daniel Kachhap wrote:
hi,
The patches in the series are work in progress and as discussed with Al Stone and Hanjun include changes in the GTDT acpi table to add missing elements for ARM platforms. Elements added are Timer frequency, interrupt count(currently 8 supported), timer ID(This will be used to invoke the correct controller).
Still more TODO's are identified.
- To add timer clock names.
- if this __init invoking mechanism is finalised then other similar devices can use this like clock, GIC etc.
- GTDT can ultimately be made CTDT(Common timer descriptor table) to other classes of timers like external exynos MCT.
Changes in V2:
- Added new fields in GTDT acpi table.
- Infrastructure to invoke the correct timer controller.
Thanks in advance. Amit
Amit Daniel Kachhap (6): irqdomain: Add a new API irq_create_default_mapping ACPI: ARM: Update acpi_register_gsi to register with the core IRQ subsystem irqchip: gic: Fix to make dt node check optional in case of ACPI acpi: gtdt: Update GTDT tables to add more fields clocksource:acpi: Add macro CLOCKSOURCE_ACPI_DECLARE clocksource: arch_timer: acpi: Use GTDT table to gather data
drivers/acpi/plat/arm/boot.c | 27 +++++++- drivers/clocksource/arm_arch_timer.c | 111 +++++++++++++++++++++++++++++----- drivers/clocksource/clksrc-of.c | 32 ++++++++++ drivers/irqchip/irq-gic.c | 2 + include/acpi/actbl3.h | 22 +++++++ include/asm-generic/vmlinux.lds.h | 6 ++ include/linux/clocksource.h | 13 ++++ include/linux/irqdomain.h | 2 + kernel/irq/irqdomain.c | 35 +++++++++++ 9 files changed, 232 insertions(+), 18 deletions(-)
This is a *really* interesting approach to the problem. I think I like it :). I've read through the patches a couple of times but I'm still sorting out my thoughts so I'm going to think on them a little longer. My initial reactions are pretty positive, though.
One thing that occurs to me is that we should probably fix iasl to match the table change, and that perhaps we should consider recommending a change to the ACPI spec to match the table change (both relatively straightforward things to do, really).
Hanjun: any comments from your side?
On 11 October 2013 08:02, Al Stone al.stone@linaro.org wrote:
On 10/09/2013 05:47 AM, Amit Daniel Kachhap wrote:
hi,
The patches in the series are work in progress and as discussed with Al Stone and Hanjun include changes in the GTDT acpi table to add missing elements for ARM platforms. Elements added are Timer frequency, interrupt count(currently 8 supported), timer ID(This will be used to invoke the correct controller).
Still more TODO's are identified.
- To add timer clock names.
- if this __init invoking mechanism is finalised then other similar
devices can use this like clock, GIC etc.
- GTDT can ultimately be made CTDT(Common timer descriptor table) to
other classes of timers like external exynos MCT.
Changes in V2:
- Added new fields in GTDT acpi table.
- Infrastructure to invoke the correct timer controller.
Thanks in advance. Amit
Amit Daniel Kachhap (6): irqdomain: Add a new API irq_create_default_mapping ACPI: ARM: Update acpi_register_gsi to register with the core IRQ subsystem irqchip: gic: Fix to make dt node check optional in case of ACPI acpi: gtdt: Update GTDT tables to add more fields clocksource:acpi: Add macro CLOCKSOURCE_ACPI_DECLARE clocksource: arch_timer: acpi: Use GTDT table to gather data
drivers/acpi/plat/arm/boot.c | 27 +++++++- drivers/clocksource/arm_arch_**timer.c | 111 +++++++++++++++++++++++++++++-**---- drivers/clocksource/clksrc-of.**c | 32 ++++++++++ drivers/irqchip/irq-gic.c | 2 + include/acpi/actbl3.h | 22 +++++++ include/asm-generic/vmlinux.**lds.h | 6 ++ include/linux/clocksource.h | 13 ++++ include/linux/irqdomain.h | 2 + kernel/irq/irqdomain.c | 35 +++++++++++ 9 files changed, 232 insertions(+), 18 deletions(-)
This is a *really* interesting approach to the problem. I think I like it :). I've read through the patches a couple of times but I'm still sorting out my thoughts so I'm going to think on them a little longer. My initial reactions are pretty positive, though.
One thing that occurs to me is that we should probably fix iasl to match the table change, and that perhaps we should consider recommending a change to the ACPI spec to match the table change (both relatively straightforward things to do, really).
Hanjun: any comments from your side?
sorry for taking so long to come back. I will review the patch carefully tomorrow, and give my comments :)
-- ciao, al ------------------------------**----- Al Stone Software Engineer Linaro Enterprise Group al.stone@linaro.org ------------------------------**-----
On 2013?10?11? 08:02, Al Stone wrote:
On 10/09/2013 05:47 AM, Amit Daniel Kachhap wrote:
hi,
The patches in the series are work in progress and as discussed with Al Stone and Hanjun include changes in the GTDT acpi table to add missing elements for ARM platforms. Elements added are Timer frequency, interrupt count(currently 8 supported), timer ID(This will be used to invoke the correct controller).
Still more TODO's are identified.
- To add timer clock names.
- if this __init invoking mechanism is finalised then other similar
devices can use this like clock, GIC etc.
- GTDT can ultimately be made CTDT(Common timer descriptor table) to
other classes of timers like external exynos MCT.
Changes in V2:
- Added new fields in GTDT acpi table.
- Infrastructure to invoke the correct timer controller.
Thanks in advance. Amit
Amit Daniel Kachhap (6): irqdomain: Add a new API irq_create_default_mapping ACPI: ARM: Update acpi_register_gsi to register with the core IRQ subsystem irqchip: gic: Fix to make dt node check optional in case of ACPI acpi: gtdt: Update GTDT tables to add more fields clocksource:acpi: Add macro CLOCKSOURCE_ACPI_DECLARE clocksource: arch_timer: acpi: Use GTDT table to gather data
drivers/acpi/plat/arm/boot.c | 27 +++++++- drivers/clocksource/arm_arch_timer.c | 111 +++++++++++++++++++++++++++++----- drivers/clocksource/clksrc-of.c | 32 ++++++++++ drivers/irqchip/irq-gic.c | 2 + include/acpi/actbl3.h | 22 +++++++ include/asm-generic/vmlinux.lds.h | 6 ++ include/linux/clocksource.h | 13 ++++ include/linux/irqdomain.h | 2 + kernel/irq/irqdomain.c | 35 +++++++++++ 9 files changed, 232 insertions(+), 18 deletions(-)
This is a *really* interesting approach to the problem. I think I like it :). I've read through the patches a couple of times but I'm still sorting out my thoughts so I'm going to think on them a little longer. My initial reactions are pretty positive, though.
One thing that occurs to me is that we should probably fix iasl to match the table change, and that perhaps we should consider recommending a change to the ACPI spec to match the table change (both relatively straightforward things to do, really).
Hanjun: any comments from your side?
I also like this patch set :) I'm not familiar with the /mechanism of /__init invoking mechanism, I will think about it more, but I really like it :)
Others are look good to me if some updates will make.
Thanks Hanjun