[PATCH 1/6] U6/U6715 ARM architecture files

Philippe Langlais philippe.langlais at stericsson.com
Fri Jun 25 09:34:47 EDT 2010


Hi,
Many thanks for your comments.

On 06/24/10 16:08, Russell King - ARM Linux wrote:
> On Thu, May 27, 2010 at 10:27:27AM +0200, Philippe Langlais wrote:
>    
>> diff --git a/arch/arm/mach-u67xx/devices.c b/arch/arm/mach-u67xx/devices.c
>> new file mode 100644
>> index 0000000..0ead380
>> --- /dev/null
>> +++ b/arch/arm/mach-u67xx/devices.c
>> @@ -0,0 +1,95 @@
>> +/*
>> + * linux/arch/arm/mach-u67xx/devices.c
>> + *
>> + * Copyright (C) ST-Ericsson SA 2010
>> + * Author: Philippe Langlais<philippe.langlais at stericsson.com>  for ST-Ericsson.
>> + * License terms:  GNU General Public License (GPL), version 2
>> + *
>> + * Device specification for the U67XX
>> + */
>> +
>> +#include<linux/kernel.h>
>> +#include<linux/init.h>
>> +#include<linux/device.h>
>> +#include<linux/ioport.h>
>> +#include<linux/platform_device.h>
>> +#include<linux/fs.h>
>> +#include<mach/hardware.h>
>> +#include<mach/scon.h>
>> +#include<mach/gpio.h>
>>      
> linux/gpio.h
>
>    
>> +struct gpio_bank u6_gpio_bank[6] = {
>> +     {(void __iomem *)GPIOA_PINS_REG, (void __iomem *)SCON_SYSMUX0_REG},
>> +     {(void __iomem *)GPIOB_PINS_REG, (void __iomem *)SCON_SYSMUX2_REG},
>> +     {(void __iomem *)GPIOC_PINS_REG, (void __iomem *)SCON_SYSMUX4_REG},
>> +     {(void __iomem *)GPIOD_PINS_REG, (void __iomem *)SCON_SYSMUX6_REG},
>> +     {(void __iomem *)GPIOE_PINS_REG, (void __iomem *)SCON_SYSMUX8_REG},
>> +     {(void __iomem *)GPIOF_PINS_REG, (void __iomem *)SCON_SYSMUX10_REG},
>>      
> Would be nice to get rid of these casts - instead moving them to the
> point of definition instead - or maybe doing as other platforms do and
> defining an IOMEM() macro which does the cast and using that in the
> definitions.
>
> iow, something like:
>
> #define IOMEM(x)        ((void __iomem *)(x))
>
> #define GPIOA_PINS_REG  IOMEM(whatever)
>
> and if you need GPIOA_PINS_REG to be usable in assembly, arrange for
> the IOMEM() macro to handle that for you.
>
>    
OK, it's already done in PATCH 5/6, I made a mistake at patch build.
I'll delete GPIO stuff from this patch.
>> diff --git a/arch/arm/plat-u6xxx/include/mach/entry-macro.S b/arch/arm/plat-u6xxx/include/mach/entry-macro.S
>> new file mode 100644
>> index 0000000..59bb2d2
>> --- /dev/null
>> +++ b/arch/arm/plat-u6xxx/include/mach/entry-macro.S
>> @@ -0,0 +1,32 @@
>> +/*
>> + * linux/arch/arm/plat-u6xxx/include/mach/entry-macro.S
>> + *
>> + * Low-level IRQ helper macros for U6-based platforms
>> + * Copyright (C) ST-Ericsson SA 2010
>> + *
>> + * This file is licensed under  the terms of the GNU General Public
>> + * License version 2. This program is licensed "as is" without any
>> + * warranty of any kind, whether express or implied.
>> + */
>> +#include<mach/hardware.h>
>> +#include<mach/irqs.h>
>> +
>> +     .macro  arch_ret_to_user, tmp1, tmp2
>> +     .endm
>> +
>> +     .macro  disable_fiq
>> +     .endm
>> +
>> +     .macro  get_irqnr_preamble, base, tmp
>> +     .endm
>>      
> This macro is there to allow you to be a little more efficient - rather
> than reloading the base address of the interrupt controller each time
> around the interrupt handling loop, you can put it in the above macro
> to take it outside the loop.
>
>    
OK
>> +#define hw_raw_local_irq_save       raw_local_irq_save
>> +#define hw_raw_local_irq_restore    raw_local_irq_restore
>>      
> What's the purpose of these additional aliases?
>
>    
Necessary for our para-virtualized drivers, but not for normal kernel usage.
Will be removed.
>> +/* INTC PRIOMASK_IRQ Register (32 bits) */
>> +#define INTC_PRIOMASK_IRQ_OFFSET 0x0
>> +#define INTC_PRIOMASK_IRQ_REG  IO_ADDRESS(INTC_BASE + INTC_PRIOMASK_IRQ_OFFSET)
>> +
>> +/* INTC PRIOMASK_FIQ Register (32 bits) */
>> +#define INTC_PRIOMASK_FIQ_OFFSET 0x4
>> +#define INTC_PRIOMASK_FIQ_REG  IO_ADDRESS(INTC_BASE + INTC_PRIOMASK_FIQ_OFFSET)
>> +
>> +/* INTC VECTOR_IRQ Register (32 bits) */
>> +#define INTC_VECTOR_IRQ_OFFSET   0x100
>> +#define INTC_VECTOR_IRQ_REG      IO_ADDRESS(INTC_BASE + INTC_VECTOR_IRQ_OFFSET)
>> +
>> +/* INTC VECTOR_FIQ Register (32 bits) */
>> +#define INTC_VECTOR_FIQ_OFFSET   0x104
>> +#define INTC_VECTOR_FIQ_REG      IO_ADDRESS(INTC_BASE + INTC_VECTOR_FIQ_OFFSET)
>> +
>> +/* INTC PENDING_* Registers (32 bits) */
>> +#define INTC_PENDING_1_OFFSET    0x200
>> +#define INTC_PENDING_2_OFFSET    0x204
>> +#define INTC_PENDING_3_OFFSET    0x208
>> +#define INTC_FEATURES_OFFSET     0x300
>> +
>> +/* INTC REQUEST 64 Registers (32 bits) */
>> +#define INTC_REQUEST1_OFFSET     0x404
>> +#define INTC_REQUEST64_OFFSET    0x500
>> +
>> +/* INTC MOD_ID Register (32 bits) */
>> +#define INTC_MOD_ID_OFFSET       0xFFC
>> +
>> +/* interrupt x [1..64] request configuration */
>> +#define INTC_REQUESTx(x)  IO_ADDRESS(INTC_BASE+INTC_REQUEST1_OFFSET+(x-1)*4)
>> +
>> +/* EXTINTx [0..23] configuration register */
>> +#define EXTINT_CFGx(x)    IO_ADDRESS(EXTINT_BASE+(x)*4)
>>      
> Does it really make sense to export all these definitions to the entire
> kernel?
>
>    
I'll try to move it into plat-u6xxx/irq.c
>> diff --git a/arch/arm/plat-u6xxx/include/mach/memory.h b/arch/arm/plat-u6xxx/include/mach/memory.h
>> new file mode 100644
>> index 0000000..0fa6cea
>> --- /dev/null
>> +++ b/arch/arm/plat-u6xxx/include/mach/memory.h
>> @@ -0,0 +1,24 @@
>> +/*
>> + * linux/arch/arm/plat-u6xxx/include/mach/memory.h
>> + *
>> + * Copyright (C) ST-Ericsson SA 2010
>> + * Author: Philippe Langlais<philippe.langlais at stericsson.com>  for ST-Ericsson.
>> + * License terms:  GNU General Public License (GPL), version 2
>> + */
>> +
>> +#ifndef __ASM_ARCH_MEMORY_H
>> +#define __ASM_ARCH_MEMORY_H
>> +
>> +/*
>> + * Physical DRAM offset.
>> + */
>> +#define PHYS_OFFSET          UL(0x20000000)
>> +#define BOOT_PARAMS_OFFSET   (PHYS_OFFSET + 0x100)
>>      
> Does it make sense to export this to the world?
>    
I take our U300 as example, but I can change that.
>> +
>> +/**
>> + * CONSISTENT_DMA_SIZE: Size of DMA-consistent memory region.
>> + * Must be multiple of 2M,between 2MB and 14MB inclusive
>> + */
>> +#define CONSISTENT_DMA_SIZE (SZ_2M)
>>      
> It defaults to 2MB, so this definition is redundant.
>
>    
OK, no problem
>> diff --git a/arch/arm/plat-u6xxx/include/mach/platform.h b/arch/arm/plat-u6xxx/include/mach/platform.h
>> new file mode 100644
>> index 0000000..5265ccd
>> --- /dev/null
>> +++ b/arch/arm/plat-u6xxx/include/mach/platform.h
>> @@ -0,0 +1,15 @@
>> +/*
>> + * linux/arch/arm/plat-u6xxx/include/mach/platform.h
>> + *
>> + * Copyright (C) ST-Ericsson SA 2010
>> + * Author: Philippe Langlais<philippe.langlais at stericsson.com>  for ST-Ericsson.
>> + * License terms:  GNU General Public License (GPL), version 2
>> + */
>> +
>> +#ifndef __ASM_ARCH_PLATFORM_H
>> +#define __ASM_ARCH_PLATFORM_H                     1
>> +
>> +#include<linux/types.h>
>> +#include<mach/hardware.h>
>> +
>> +#endif  /* __ASM_ARCH_PLATFORM_H */
>>      
> If there's nothing required in this file, it doesn't need to exist.
>
>    
OK
>> diff --git a/arch/arm/plat-u6xxx/include/mach/timer.h b/arch/arm/plat-u6xxx/include/mach/timer.h
>> new file mode 100644
>> index 0000000..049e72d
>> --- /dev/null
>> +++ b/arch/arm/plat-u6xxx/include/mach/timer.h
>> @@ -0,0 +1,24 @@
>> +/*
>> + *  linux/arch/arm/plat-u6xxx/include/mach/timer.h
>> + *
>> + * Copyright (C) ST-Ericsson SA 2010
>> + * Author: Philippe Langlais<philippe.langlais at stericsson.com>  for ST-Ericsson.
>> + * License terms:  GNU General Public License (GPL), version 2
>> + */
>> +
>> +#ifndef __PLAT_TIMER_H
>> +#define __PLAT_TIMER_H
>> +#ifdef U6_TIMER_C
>> +#define PUBLIC
>> +#else
>> +#define PUBLIC extern
>> +#endif
>>      
> Err, no - there's really no need for such hacks in C, and I can't find
> anywhere which defines U6_TIMER_C.
>
>    
OK
>> +
>> +struct sys_timer;
>> +
>> +PUBLIC struct sys_timer u6_timer;
>> +
>> +PUBLIC void __init u6_timer_init(void);
>> +
>> +#undef PUBLIC
>> +#endif
>>      
>    
>> diff --git a/arch/arm/plat-u6xxx/include/mach/vmalloc.h b/arch/arm/plat-u6xxx/include/mach/vmalloc.h
>> new file mode 100644
>> index 0000000..583033f
>> --- /dev/null
>> +++ b/arch/arm/plat-u6xxx/include/mach/vmalloc.h
>> @@ -0,0 +1,10 @@
>> +/*
>> + * linux/arch/arm/plat-u6/include/mach/vmalloc.h
>> + * Copyright (C) ST-Ericsson SA 2010
>> + * Author: Philippe Langlais<philippe.langlais at stericsson.com>  for ST-Ericsson.
>> + * License terms:  GNU General Public License (GPL), version 2
>> + *
>> + * Virtual memory allocations
>> + * End must be above the I/O registers and on an even 2MiB boundary.
>> + */
>> +#define VMALLOC_END       (PAGE_OFFSET + 0x28000000)
>>      
> Is the upper limit of vmalloc space is dependent on PAGE_OFFSET?  If
> not, then it shouldn't be using a calculation based upon that value.
>
>    
OK
>> diff --git a/arch/arm/plat-u6xxx/timer.c b/arch/arm/plat-u6xxx/timer.c
>> new file mode 100644
>> index 0000000..62f13f5
>> --- /dev/null
>> +++ b/arch/arm/plat-u6xxx/timer.c
>> @@ -0,0 +1,679 @@
>> +/*
>> + * linux/arch/arm/plat-u6xxx/timer.c
>> + *
>> + * Copyright (C) ST-Ericsson SA 2010
>> + * Author: Vincent Guittot<vincent.guittot at stericsson.com>  for ST-Ericsson.
>> + * License terms:  GNU General Public License (GPL), version 2
>> + */
>> +
>> +#include<linux/types.h>
>> +#include<linux/kernel.h>
>> +#include<linux/err.h>
>> +#include<linux/init.h>
>> +#include<linux/io.h>
>> +
>> +#include<asm/mach/time.h>
>> +
>> +#include<mach/hardware.h>
>> +
>> +#include<asm/mach/irq.h>
>> +#include<linux/interrupt.h>
>> +#include<mach/irqs.h>
>> +
>> +#include<linux/clk.h>
>> +
>> +#include<linux/clocksource.h>
>> +#include<linux/clockchips.h>
>>      
> linux/ includes before asm/ includes.  asm/ includes before mach/ includes
> please.
>
>    
OK
>> +#undef U6_TIMER_DEBUG
>> +#if defined(U6_TIMER_DEBUG)
>> +#define debug(fmt, args...)                                          \
>> +     printk(PKMOD fmt, ## args)
>> +#else
>> +#define debug(fmt, args...)
>> +#endif
>>      
> You could use pr_debug() instead, and define 'DEBUG' at the top of the
> file you want debug messages from.
>    
OK
>    
>> +static irqreturn_t
>> +u6_mmtu_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
>> +{
>> +     uint8_t status, enable;
>> +     struct mmtu_ctxt *mmtu;
>> +
>> +     mmtu = u6_mmtu_get_context(0);
>> +
>> +     status = readl((mmtu->base + MMTU_INT_OFFSET + MMTU_INT_STATUS_IDX));
>> +     enable = readl((mmtu->base + MMTU_INT_OFFSET + MMTU_INT_ENABLE_IDX));
>> +
>> +     debug("mmtu_timer_interrupt %d\n", status);
>> +
>> +     if (status&  enable&  MMTU_IRQ_MASK) {
>> +             struct clock_event_device *evt =&clockevent_mmtu;
>> +
>> +             writel(MMTU_IRQ_MASK, (mmtu->base + MMTU_INT_OFFSET
>> +                                     + MMTU_INT_CLR_STAT_IDX));
>> +
>> +             if (mmtu->autoreload)
>> +                     u6_mmtu_timer_start(mmtu->compvalue, 0);
>>      
> If your hardware doesn't do reloadable timers, you're not supposed to
> emulate it.  The generic time infrastructure contains all the code
> that's required to handle periodic timer interrupts with timers only
> capable of one-shot mode.
>
>    
We removed this code and it's works => OK
>    
>> +             else
>> +                     writel(MMTU_IRQ_MASK,
>> +                            (mmtu->base + MMTU_INT_OFFSET +
>> +                             MMTU_INT_CLR_ENA_IDX));
>> +
>> +             if (evt->event_handler)
>> +                     evt->event_handler(evt);
>> +     }
>> +     return IRQ_HANDLED;
>> +}
>> +
>> +static struct irqaction u6_mmtu_timer_irq = {
>> +     .name = "U6 MMTU timer Tick",
>> +     .flags = IRQF_DISABLED,
>> +     .handler = (irq_handler_t) u6_mmtu_timer_interrupt,
>> +};
>> +
>> +static inline void u6_mmtu_clk_enable(int id)
>> +{
>> +     struct mmtu_ctxt *mmtu = u6_mmtu_get_context(id);
>> +
>> +     /* Clock Multimedia Timer Unit.
>> +      */
>> +     if ((mmtu->clk != NULL)&&  (mmtu->mode == 0)) {
>> +             debug("mmtu_clk_enable\n");
>> +             mmtu->mode = 1;
>> +             clk_enable(mmtu->clk);
>> +     }
>> +}
>> +
>> +static inline void u6_mmtu_clk_disable(int id)
>> +{
>> +     struct mmtu_ctxt *mmtu = u6_mmtu_get_context(id);
>> +
>> +     /* Clock Multimedia Timer Unit.
>> +      */
>> +     if ((mmtu->clk != NULL)&&  (mmtu->mode == 1)) {
>> +             debug("mmtu_clk_disable\n");
>> +             clk_disable(mmtu->clk);
>> +             mmtu->mode = 0;
>> +     }
>> +}
>> +
>> +static inline int u6_mmtu_timer_start(unsigned long cycles, int id)
>> +{
>> +     struct mmtu_ctxt *mmtu = u6_mmtu_get_context(id);
>> +
>> +     debug("mmtu_timer_start %d\n", cycles);
>> +     u6_mmtu_clk_enable(id);
>> +
>> +     /* MMTU limitation : can't set a value smaller or equal to tcval + 1 */
>> +     cycles = cycles<  2 ? 2 : cycles;
>> +
>> +     mmtu->compvalue = cycles;
>> +
>> +     mmtu->endvalue = mmtu->compvalue
>> +             + readl((mmtu->base + MMTU_TCVAL_IDX));
>> +
>> +     writel(MMTU_IRQ_MASK,
>> +            (mmtu->base + MMTU_INT_OFFSET + MMTU_INT_CLR_STAT_IDX));
>> +
>> +     writel(mmtu->endvalue, (mmtu->base + MMTU_USED_MATCH_IDX));
>> +
>> +     writel(MMTU_IRQ_MASK,
>> +            (mmtu->base + MMTU_INT_OFFSET + MMTU_INT_SET_ENA_IDX));
>> +
>> +     /* the value has already expired */
>> +     if ((mmtu->endvalue<= readl((mmtu->base + MMTU_TCVAL_IDX)))
>> +&&  (mmtu->endvalue>  mmtu->compvalue)
>> +&&  !(readl((mmtu->base + MMTU_INT_OFFSET
>> +                                 + MMTU_INT_STATUS_IDX))&  MMTU_IRQ_MASK))
>> +             writel(MMTU_IRQ_MASK, (mmtu->base + MMTU_INT_OFFSET
>> +                                     + MMTU_INT_SET_STAT_IDX));
>> +
>> +     return 0;
>> +}
>> +
>> +static int u6_mmtu_timer_init(int id, unsigned long reload,
>> +                          unsigned long prescale, int over_it)
>> +{
>> +
>> +     struct mmtu_ctxt *mmtu = u6_mmtu_get_context(id);
>> +
>> +     debug("mmtu_timer_init %d\n", id);
>> +
>> +     /* Enable clock */
>> +/*
>> +     u6_mmtu_clk_enable(id);
>> +     clk mngt not available yet
>> +     directly enable it
>> +*/
>> +     {
>> +             unsigned long flags;
>> +             unsigned long reg;
>> +             hw_raw_local_irq_save(flags);
>> +             reg = readl(CGU_GATESC2_REG);
>> +             reg |= 0x1<<  2;
>> +             writel(reg, CGU_GATESC2_REG);
>> +             hw_raw_local_irq_restore(flags);
>> +     }
>> +
>> +     /* Reset timer */
>> +     /* reset control register */
>> +     writel(0x0000, (mmtu->base + MMTU_CON_IDX));
>> +     writel(0x0002, (mmtu->base + MMTU_CON_IDX));
>> +     /* reset control register */
>> +     writel(0x0000, (mmtu->base + MMTU_CON_IDX));
>> +
>> +     /* clear whole enable irq register */
>> +     writel(0xFF, (mmtu->base + MMTU_INT_OFFSET + MMTU_INT_CLR_ENA_IDX));
>> +     /* clear whole status register */
>> +     writel(0xFF, (mmtu->base + MMTU_INT_OFFSET + MMTU_INT_CLR_STAT_IDX));
>> +
>> +     /* reset pre-scaler reload register */
>> +     writel(0x00000000, (mmtu->base + MMTU_PRESCALER_IDX));
>> +
>> +     /* reset match control register */
>> +     writel(0x0000, (mmtu->base + MMTU_MATCH_CON_IDX));
>> +     /* reset match 0 register */
>> +     writel(0x00000000, (mmtu->base + MMTU_MATCH0_IDX));
>> +     /* reset match 1 register */
>> +     writel(0x00000000, (mmtu->base + MMTU_MATCH1_IDX));
>> +
>> +     /* Initialize timer */
>> +     writel(prescale - 1, (mmtu->base + MMTU_PRESCALER_IDX));
>> +     /* power of 2 system clock */
>> +     writel(reload, (mmtu->base + MMTU_MATCH0_IDX));
>> +
>> +     /* enable counter register */
>> +     writel(0x0001, (mmtu->base + MMTU_CON_IDX));
>> +
>> +     /* clear whole status register */
>> +     writel(0xFF, (mmtu->base + MMTU_INT_OFFSET + MMTU_INT_CLR_STAT_IDX));
>> +
>> +     if (id == 0)
>> +             setup_irq(IRQ_MMTU,&u6_mmtu_timer_irq);
>> +
>> +     /* Disable clock */
>> +#ifndef U6_MMTU_CLOCK_SOURCE
>> +     u6_mmtu_clk_disable(id);
>> +#endif
>> +     return 0;
>> +}
>> +
>> +/*** MMTU Clock event device ***/
>> +
>> +static int u6_mmtu_set_next_event(unsigned long cycles,
>> +                              struct clock_event_device *evt)
>> +{
>> +     debug("mmtu_set_next_event %d\n", cycles);
>> +     u6_mmtu_timer_start(cycles, 0);
>> +
>> +     return 0;
>> +}
>> +
>> +static void u6_mmtu_set_mode(enum clock_event_mode mode,
>> +                         struct clock_event_device *evt)
>> +{
>> +     struct mmtu_ctxt *mmtu = u6_mmtu_get_context(0);
>> +     unsigned long reg;
>> +
>> +     debug("mmtu_set_mode %d\n", mode);
>> +
>> +     switch (mode) {
>> +     case CLOCK_EVT_MODE_UNUSED:
>> +             writel(MMTU_IRQ_MASK,
>> +                    (mmtu->base + MMTU_INT_OFFSET + MMTU_INT_CLR_ENA_IDX));
>> +             writel(MMTU_IRQ_MASK,
>> +                    (mmtu->base + MMTU_INT_OFFSET + MMTU_INT_CLR_STAT_IDX));
>> +
>> +             reg = readl((mmtu->base + MMTU_TCVAL_IDX));
>> +             writel(reg - 1, (mmtu->base + MMTU_USED_MATCH_IDX));
>> +
>> +#ifndef U6_MMTU_CLOCK_SOURCE
>> +             u6_mmtu_clk_disable(0);
>> +
>> +             if (mmtu->clk != NULL)
>> +                     clk_put(mmtu->clk);
>> +#endif
>> +             mmtu->autoreload = 0;
>> +             break;
>> +     case CLOCK_EVT_MODE_SHUTDOWN:
>> +             mmtu->autoreload = 0;
>> +
>> +             if (mmtu->clk == NULL) {
>> +                     mmtu->clk = clk_get(0, "MMTU");
>> +                     if (IS_ERR(mmtu->clk))
>> +                             mmtu->clk = NULL;
>> +             }
>> +
>> +             writel(MMTU_IRQ_MASK,
>> +                    (mmtu->base + MMTU_INT_OFFSET + MMTU_INT_CLR_STAT_IDX));
>> +             writel(MMTU_IRQ_MASK,
>> +                    (mmtu->base + MMTU_INT_OFFSET + MMTU_INT_SET_ENA_IDX));
>> +     case CLOCK_EVT_MODE_ONESHOT:
>> +     case CLOCK_EVT_MODE_RESUME:
>> +             mmtu->autoreload = 0;
>> +             break;
>> +     case CLOCK_EVT_MODE_PERIODIC:
>> +             writel(MMTU_IRQ_MASK,
>> +                    (mmtu->base + MMTU_INT_OFFSET + MMTU_INT_SET_ENA_IDX));
>> +             mmtu->autoreload = 1;
>> +             break;
>> +     }
>> +}
>> +
>> +static void u6_clockevent_init_mmtu(void)
>> +{
>> +     printk(PKMOD "clockevent_init_mmtu\n");
>> +
>> +     /* prescale 13Mhz ->  1Mhz */
>> +#ifndef U6_MMTU_CLOCK_SOURCE
>> +     u6_mmtu_timer_init(0, 0, (MMTU_SYS_FRQ / MMTU_ROOT_FRQ), 0);
>> +#endif
>> +
>> +/* issue it is shorter than reality and generates spurious irq */
>> +/*      clockevent_mmtu.mult = div_sc(MMTU_ROOT_FRQ, NSEC_PER_SEC,
>> + *      clockevent_mmtu.shift) + 1;*/
>> +     clockevent_mmtu.mult =
>> +         div_sc(MMTU_ROOT_FRQ, NSEC_PER_SEC, clockevent_mmtu.shift);
>> +
>> +/*      clockevent_mmtu.max_delta_ns = div_sc(RELOAD_COUNTER_MMTU,
>> + *      clockevent_mmtu.mult, clockevent_mmtu.shift);*/
>> +/*  In fact it is wider than the 32bits variable !!! */
>> +     clockevent_mmtu.max_delta_ns = 0xFFFFFFFF;
>> +
>> +/*  MMTU HW limitation: match register can't be set w/ tcval+1 */
>> +/*      clockevent_mmtu.min_delta_ns = div_sc(1, clockevent_mmtu.mult,
>> + *      clockevent_mmtu.shift)+1;*/
>> +     clockevent_mmtu.min_delta_ns =
>> +         div_sc(2, clockevent_mmtu.mult, clockevent_mmtu.shift) + 1;
>> +     /* avoid to much timer interrupt with 10us min between 2 irq */
>> +     if (clockevent_mmtu.min_delta_ns<  10000)
>> +             clockevent_mmtu.min_delta_ns = 10000;
>> +     else if (clockevent_mmtu.max_delta_ns<  10000)
>> +             clockevent_mmtu.min_delta_ns = clockevent_mmtu.max_delta_ns>>1;
>> +
>> +     clockevent_mmtu.cpumask = get_cpu_mask(0);
>> +     clockevents_register_device(&clockevent_mmtu);
>> +
>> +     u6_mmtu_set_next_event(MMTU_ROOT_FRQ / HZ,&clockevent_mmtu);
>> +}
>> +
>> +/*** MMTU Clock source device ***/
>> +#ifdef U6_MMTU_CLOCK_SOURCE
>> +
>> +static cycle_t u6_mmtu_read(struct clocksource *source)
>> +{
>> +     struct mmtu_ctxt *mmtu = u6_mmtu_get_context(0);
>> +
>> +     return readl((mmtu->base + MMTU_TCVAL_IDX))&  source->mask;
>> +}
>>      
> Clocksource read functions don't require the value masking.
>    
OK
>    
>> +
>> +static void u6_clocksource_init_mmtu(void)
>> +{
>> +     printk(PKMOD "clocksource_init_mmtu\n");
>> +
>> +     if (MMTU_ROOT_FRQ>= 1000000)
>> +             clocksource_mmtu.mult =
>> +                 clocksource_khz2mult((MMTU_ROOT_FRQ / 1000),
>> +                                      clocksource_mmtu.shift);
>> +     else
>> +             clocksource_mmtu.mult = clocksource_hz2mult((MMTU_ROOT_FRQ),
>> +                             clocksource_mmtu.shift);
>> +
>> +     u6_mmtu_timer_init(0, 0, (MMTU_SYS_FRQ / MMTU_ROOT_FRQ), 0);
>> +
>> +     clocksource_register(&clocksource_mmtu);
>> +}
>> +
>> +unsigned long long u6_mmtu_time(void)
>> +{
>> +     unsigned long long ticks64 = u6_mmtu_read(&clocksource_mmtu);
>> +
>> +     return (ticks64 * clocksource_mmtu.mult)>>  clocksource_mmtu.shift;
>> +}
>>      
> Can you explain the purpose of this function please, and why you export
> the ticks and value from this function via sysfs?
>    
It's for debug purpose, can be removed for standard kernel.
>    
>> +#endif
>> +
>> +/*** SysFs interface ***/
>> +/***********************/
>> +#ifdef CONFIG_U6_POWER_SYSFS
>> +
>> +/*** Clock event sysfs interface **/
>> +
>> +#define shows_one_evt(file_name, object)                             \
>> +static ssize_t show_##file_name##_evt                                        \
>> +(struct kobject *kobj, char *buf)                            \
>> +{                                                                    \
>> +     return sprintf(buf, "%s\n", clockevent_mmtu.object);            \
>> +}
>> +
>> +#define showu_one_evt(file_name, object)                             \
>> +static ssize_t show_##file_name##_evt                                        \
>> +(struct kobject *kobj, char *buf)                            \
>> +{                                                                    \
>> +     return sprintf(buf, "%u\n", clockevent_mmtu.object);            \
>> +}
>> +
>> +#define showlu_one_evt(file_name, object)                            \
>> +static ssize_t show_##file_name##_evt                                        \
>> +(struct kobject *kobj, char *buf)                            \
>> +{                                                                    \
>> +     return sprintf(buf, "%lu\n", clockevent_mmtu.object);           \
>> +}
>> +
>> +#define storelu_one_evt(file_name, object)                           \
>> +static ssize_t store_##file_name##_evt                                       \
>> +(struct kobject *kobj, const char *buf, size_t size)                 \
>> +{                                                                    \
>> +     unsigned long object; \
>> +     strict_strtoul(buf, 10,&object); \
>> +     clockevent_mmtu.object = object; \
>> +     return size;            \
>> +}
>> +
>> +#define showx_one_evt(file_name, object)                             \
>> +static ssize_t show_##file_name##_evt                                        \
>> +(struct kobject *kobj, char *buf)                            \
>> +{                                                                    \
>> +     return sprintf(buf, "0x%x\n", clockevent_mmtu.object);          \
>> +}
>> +
>> +shows_one_evt(name, name);
>> +showu_one_evt(rating, rating);
>> +showlu_one_evt(mult, mult);
>> +#ifdef CONFIG_U6_TIMER_TUNE
>> +storelu_one_evt(mult, mult);
>> +#endif
>> +showu_one_evt(shift, shift);
>> +showx_one_evt(features, features);
>> +showlu_one_evt(min_delta_ns, min_delta_ns);
>> +showlu_one_evt(max_delta_ns, max_delta_ns);
>>      
> Why do you want all these parameters exported to userspace?  Maybe you
> should discuss your requirement here with the generic time people
> before submitting it?
>    
For debug only => removed all


I'll fix this patch next week and send it to the list.

Regards,
Philippe




More information about the linux-arm-kernel mailing list