From patchwork Mon Apr 22 09:51:44 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Linus Walleij X-Patchwork-Id: 16293 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-gh0-f198.google.com (mail-gh0-f198.google.com [209.85.160.198]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id DA0D325DEE for ; Mon, 22 Apr 2013 09:53:16 +0000 (UTC) Received: by mail-gh0-f198.google.com with SMTP id r11sf8649720ghr.5 for ; Mon, 22 Apr 2013 02:52:30 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-received:x-beenthere:x-received:received-spf:x-received :x-forwarded-to:x-forwarded-for:delivered-to:x-received:received-spf :from:to:cc:subject:date:message-id:x-mailer:mime-version :x-gm-message-state:x-original-sender :x-original-authentication-results:precedence:mailing-list:list-id :x-google-group-id:list-post:list-help:list-archive:list-unsubscribe :content-type; bh=+Sa1WczyKJEcelAcZhCGLV+6lQ1pv8Jd/Q8xvpPC8Ow=; b=oInGc+8hrdXL/4BtlMbiXiM9Pe7kgie3pasqqqd2qBnMBPPadNcIdbZsqkNmF9jYuw P0ktAXOYK7EPq6eQrp5S/hweNEdX61cK5Tg2n0VaruN5vDUTKvjs5aBpnS9Y+ShKl7wt 73UPhmnKpXAgONttWIL3pEwX+bzkDCZH62Rwhd5+I37wyABh0PzN0vUVdOJJPUyGkYH6 q5y3J1G3fQ+dMEbjc8mBKnlYW1lMHy9tE/AWfqGR8JZ5XYVf7iDCLUv2ErUpalakxmUn WMI015JBebhQZsD3GhHOLEXjtfIGUh3M1jEAZn8ScSsHSE5uyGMm3R6WZjjL3OhzwXQf EC5w== X-Received: by 10.236.87.177 with SMTP id y37mr12717721yhe.15.1366624350814; Mon, 22 Apr 2013 02:52:30 -0700 (PDT) X-BeenThere: patchwork-forward@linaro.org Received: by 10.49.121.37 with SMTP id lh5ls2919535qeb.66.gmail; Mon, 22 Apr 2013 02:52:30 -0700 (PDT) X-Received: by 10.220.223.202 with SMTP id il10mr18668101vcb.4.1366624350506; Mon, 22 Apr 2013 02:52:30 -0700 (PDT) Received: from mail-vc0-f182.google.com (mail-vc0-f182.google.com [209.85.220.182]) by mx.google.com with ESMTPS id ec8si15554813vdb.46.2013.04.22.02.52.30 (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Mon, 22 Apr 2013 02:52:30 -0700 (PDT) Received-SPF: neutral (google.com: 209.85.220.182 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) client-ip=209.85.220.182; Received: by mail-vc0-f182.google.com with SMTP id ht11so3730327vcb.13 for ; Mon, 22 Apr 2013 02:52:30 -0700 (PDT) X-Received: by 10.58.144.170 with SMTP id sn10mr13783154veb.7.1366624350377; Mon, 22 Apr 2013 02:52:30 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patches@linaro.org Received: by 10.58.127.98 with SMTP id nf2csp68663veb; Mon, 22 Apr 2013 02:52:29 -0700 (PDT) X-Received: by 10.180.36.48 with SMTP id n16mr64689053wij.30.1366624349230; Mon, 22 Apr 2013 02:52:29 -0700 (PDT) Received: from eu1sys200aog107.obsmtp.com (eu1sys200aog107.obsmtp.com [207.126.144.123]) by mx.google.com with SMTP id x41si30048820eey.82.2013.04.22.02.52.21 (version=TLSv1 cipher=RC4-SHA bits=128/128); Mon, 22 Apr 2013 02:52:29 -0700 (PDT) Received-SPF: neutral (google.com: 207.126.144.123 is neither permitted nor denied by best guess record for domain of linus.walleij@stericsson.com) client-ip=207.126.144.123; Received: from beta.dmz-us.st.com ([167.4.1.35]) (using TLSv1) by eu1sys200aob107.postini.com ([207.126.147.11]) with SMTP ID DSNKUXUIVPyizznyGak2YhbcsnOq8e2Y0Y8F@postini.com; Mon, 22 Apr 2013 09:52:28 UTC Received: from zeta.dmz-us.st.com (ns4.st.com [167.4.16.71]) by beta.dmz-us.st.com (STMicroelectronics) with ESMTP id B668148; Mon, 22 Apr 2013 09:50:52 +0000 (GMT) Received: from relay2.stm.gmessaging.net (unknown [10.230.100.18]) by zeta.dmz-us.st.com (STMicroelectronics) with ESMTP id 71DE34D; Mon, 22 Apr 2013 03:00:19 +0000 (GMT) Received: from exdcvycastm004.EQ1STM.local (alteon-source-exch [10.230.100.61]) (using TLSv1 with cipher RC4-MD5 (128/128 bits)) (Client CN "exdcvycastm004", Issuer "exdcvycastm004" (not verified)) by relay2.stm.gmessaging.net (Postfix) with ESMTPS id 49641A8074; Mon, 22 Apr 2013 11:51:43 +0200 (CEST) Received: from steludxu4075.lud.stericsson.com (10.230.100.153) by smtp.stericsson.com (10.230.100.2) with Microsoft SMTP Server (TLS) id 8.3.279.5; Mon, 22 Apr 2013 11:51:47 +0200 From: Linus Walleij To: Cc: Arnd Bergmann , , Linus Walleij Subject: [PATCH 03/23] ARM: u300: device tree support for the timer Date: Mon, 22 Apr 2013 11:51:44 +0200 Message-ID: <1366624304-6190-1-git-send-email-linus.walleij@stericsson.com> X-Mailer: git-send-email 1.7.11.3 MIME-Version: 1.0 X-Gm-Message-State: ALoCoQliSnjxvC/W6R83m0rp86ZI/QPJ/RwLzt0hRbSa6eYXA7i75tP0GUOnFYfDPCB36Xm8N5U8 X-Original-Sender: linus.walleij@stericsson.com X-Original-Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.220.182 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Precedence: list Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org List-ID: X-Google-Group-Id: 836684582541 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , From: Linus Walleij This adds device tree support for the U300 timer, by making the memory base offset and IRQ dynamically assigned, then optionally looking them up from the device tree. Since the timer needs to be registered before any platform devices are created, we will go into the device tree and look up the "/timer@c0014000" node and read our base address and IRQ from there. Signed-off-by: Linus Walleij --- .../bindings/timer/stericsson-u300-apptimer.txt | 18 ++++ arch/arm/mach-u300/timer.c | 99 ++++++++++++++-------- 2 files changed, 80 insertions(+), 37 deletions(-) create mode 100644 Documentation/devicetree/bindings/timer/stericsson-u300-apptimer.txt diff --git a/Documentation/devicetree/bindings/timer/stericsson-u300-apptimer.txt b/Documentation/devicetree/bindings/timer/stericsson-u300-apptimer.txt new file mode 100644 index 0000000..9499bc8 --- /dev/null +++ b/Documentation/devicetree/bindings/timer/stericsson-u300-apptimer.txt @@ -0,0 +1,18 @@ +ST-Ericsson U300 apptimer + +Required properties: + +- compatible : should be "stericsson,u300-apptimer" +- reg : Specifies base physical address and size of the registers. +- interrupts : A list of 4 interrupts; one for each subtimer. These + are, in order: OS (operating system), DD (device driver) both + adopted for EPOC/Symbian with two specific IRQs for these tasks, + then GP1 and GP2, which are general-purpose timers. + +Example: + +timer { + compatible = "stericsson,u300-apptimer"; + reg = <0xc0014000 0x1000>; + interrupts = <24 25 26 27>; +}; diff --git a/arch/arm/mach-u300/timer.c b/arch/arm/mach-u300/timer.c index c3d3802..5e60a5e 100644 --- a/arch/arm/mach-u300/timer.c +++ b/arch/arm/mach-u300/timer.c @@ -19,6 +19,8 @@ #include #include #include +#include +#include #include #include @@ -190,6 +192,8 @@ #define TICKS_PER_JIFFY ((CLOCK_TICK_RATE + (HZ/2)) / HZ) #define US_PER_TICK ((1000000 + (HZ/2)) / HZ) +static void __iomem *u300_timer_base; + /* * The u300_set_mode() function is always called first, if we * have oneshot timer active, the oneshot scheduling function @@ -202,28 +206,28 @@ static void u300_set_mode(enum clock_event_mode mode, case CLOCK_EVT_MODE_PERIODIC: /* Disable interrupts on GPT1 */ writel(U300_TIMER_APP_GPT1IE_IRQ_DISABLE, - U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT1IE); + u300_timer_base + U300_TIMER_APP_GPT1IE); /* Disable GP1 while we're reprogramming it. */ writel(U300_TIMER_APP_DGPT1_TIMER_DISABLE, - U300_TIMER_APP_VBASE + U300_TIMER_APP_DGPT1); + u300_timer_base + U300_TIMER_APP_DGPT1); /* * Set the periodic mode to a certain number of ticks per * jiffy. */ writel(TICKS_PER_JIFFY, - U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT1TC); + u300_timer_base + U300_TIMER_APP_GPT1TC); /* * Set continuous mode, so the timer keeps triggering * interrupts. */ writel(U300_TIMER_APP_SGPT1M_MODE_CONTINUOUS, - U300_TIMER_APP_VBASE + U300_TIMER_APP_SGPT1M); + u300_timer_base + U300_TIMER_APP_SGPT1M); /* Enable timer interrupts */ writel(U300_TIMER_APP_GPT1IE_IRQ_ENABLE, - U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT1IE); + u300_timer_base + U300_TIMER_APP_GPT1IE); /* Then enable the OS timer again */ writel(U300_TIMER_APP_EGPT1_TIMER_ENABLE, - U300_TIMER_APP_VBASE + U300_TIMER_APP_EGPT1); + u300_timer_base + U300_TIMER_APP_EGPT1); break; case CLOCK_EVT_MODE_ONESHOT: /* Just break; here? */ @@ -234,33 +238,33 @@ static void u300_set_mode(enum clock_event_mode mode, */ /* Disable interrupts on GPT1 */ writel(U300_TIMER_APP_GPT1IE_IRQ_DISABLE, - U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT1IE); + u300_timer_base + U300_TIMER_APP_GPT1IE); /* Disable GP1 while we're reprogramming it. */ writel(U300_TIMER_APP_DGPT1_TIMER_DISABLE, - U300_TIMER_APP_VBASE + U300_TIMER_APP_DGPT1); + u300_timer_base + U300_TIMER_APP_DGPT1); /* * Expire far in the future, u300_set_next_event() will be * called soon... */ - writel(0xFFFFFFFF, U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT1TC); + writel(0xFFFFFFFF, u300_timer_base + U300_TIMER_APP_GPT1TC); /* We run one shot per tick here! */ writel(U300_TIMER_APP_SGPT1M_MODE_ONE_SHOT, - U300_TIMER_APP_VBASE + U300_TIMER_APP_SGPT1M); + u300_timer_base + U300_TIMER_APP_SGPT1M); /* Enable interrupts for this timer */ writel(U300_TIMER_APP_GPT1IE_IRQ_ENABLE, - U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT1IE); + u300_timer_base + U300_TIMER_APP_GPT1IE); /* Enable timer */ writel(U300_TIMER_APP_EGPT1_TIMER_ENABLE, - U300_TIMER_APP_VBASE + U300_TIMER_APP_EGPT1); + u300_timer_base + U300_TIMER_APP_EGPT1); break; case CLOCK_EVT_MODE_UNUSED: case CLOCK_EVT_MODE_SHUTDOWN: /* Disable interrupts on GP1 */ writel(U300_TIMER_APP_GPT1IE_IRQ_DISABLE, - U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT1IE); + u300_timer_base + U300_TIMER_APP_GPT1IE); /* Disable GP1 */ writel(U300_TIMER_APP_DGPT1_TIMER_DISABLE, - U300_TIMER_APP_VBASE + U300_TIMER_APP_DGPT1); + u300_timer_base + U300_TIMER_APP_DGPT1); break; case CLOCK_EVT_MODE_RESUME: /* Ignore this call */ @@ -282,27 +286,27 @@ static int u300_set_next_event(unsigned long cycles, { /* Disable interrupts on GPT1 */ writel(U300_TIMER_APP_GPT1IE_IRQ_DISABLE, - U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT1IE); + u300_timer_base + U300_TIMER_APP_GPT1IE); /* Disable GP1 while we're reprogramming it. */ writel(U300_TIMER_APP_DGPT1_TIMER_DISABLE, - U300_TIMER_APP_VBASE + U300_TIMER_APP_DGPT1); + u300_timer_base + U300_TIMER_APP_DGPT1); /* Reset the General Purpose timer 1. */ writel(U300_TIMER_APP_RGPT1_TIMER_RESET, - U300_TIMER_APP_VBASE + U300_TIMER_APP_RGPT1); + u300_timer_base + U300_TIMER_APP_RGPT1); /* IRQ in n * cycles */ - writel(cycles, U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT1TC); + writel(cycles, u300_timer_base + U300_TIMER_APP_GPT1TC); /* * We run one shot per tick here! (This is necessary to reconfigure, * the timer will tilt if you don't!) */ writel(U300_TIMER_APP_SGPT1M_MODE_ONE_SHOT, - U300_TIMER_APP_VBASE + U300_TIMER_APP_SGPT1M); + u300_timer_base + U300_TIMER_APP_SGPT1M); /* Enable timer interrupts */ writel(U300_TIMER_APP_GPT1IE_IRQ_ENABLE, - U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT1IE); + u300_timer_base + U300_TIMER_APP_GPT1IE); /* Then enable the OS timer again */ writel(U300_TIMER_APP_EGPT1_TIMER_ENABLE, - U300_TIMER_APP_VBASE + U300_TIMER_APP_EGPT1); + u300_timer_base + U300_TIMER_APP_EGPT1); return 0; } @@ -321,8 +325,9 @@ static irqreturn_t u300_timer_interrupt(int irq, void *dev_id) { struct clock_event_device *evt = &clockevent_u300_1mhz; /* ACK/Clear timer IRQ for the APP GPT1 Timer */ + writel(U300_TIMER_APP_GPT1IA_IRQ_ACK, - U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT1IA); + u300_timer_base + U300_TIMER_APP_GPT1IA); evt->event_handler(evt); return IRQ_HANDLED; } @@ -343,12 +348,12 @@ static struct irqaction u300_timer_irq = { static u32 notrace u300_read_sched_clock(void) { - return readl(U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT2CC); + return readl(u300_timer_base + U300_TIMER_APP_GPT2CC); } static unsigned long u300_read_current_timer(void) { - return readl(U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT2CC); + return readl(u300_timer_base + U300_TIMER_APP_GPT2CC); } static struct delay_timer u300_delay_timer; @@ -360,6 +365,26 @@ void __init u300_timer_init(void) { struct clk *clk; unsigned long rate; + int irq = 0; + +#ifdef CONFIG_OF + struct device_node *timer = NULL; + + timer = of_find_node_by_path("/timer0@c0014000"); + if (timer) { + struct resource irq_res; + + u300_timer_base = of_iomap(timer, 0); + /* Get the IRQ for the GP1 timer */ + irq = of_irq_to_resource(timer, 2, &irq_res); + } +#endif + /* Fallback to static maps if base & IRQ not found in DT */ + if (!u300_timer_base) + u300_timer_base = U300_TIMER_APP_VBASE; + if (irq <= 0) + irq = IRQ_U300_TIMER_APP_GP1; + pr_info("U300 GP1 timer @ base: %p, IRQ: %d\n", u300_timer_base, irq); /* Clock the interrupt controller */ clk = clk_get_sys("apptimer", NULL); @@ -378,40 +403,40 @@ void __init u300_timer_init(void) * Example usage in cnh1601578 cpu subsystem pd_timer_app.c */ writel(U300_TIMER_APP_CRC_CLOCK_REQUEST_ENABLE, - U300_TIMER_APP_VBASE + U300_TIMER_APP_CRC); + u300_timer_base + U300_TIMER_APP_CRC); writel(U300_TIMER_APP_ROST_TIMER_RESET, - U300_TIMER_APP_VBASE + U300_TIMER_APP_ROST); + u300_timer_base + U300_TIMER_APP_ROST); writel(U300_TIMER_APP_DOST_TIMER_DISABLE, - U300_TIMER_APP_VBASE + U300_TIMER_APP_DOST); + u300_timer_base + U300_TIMER_APP_DOST); writel(U300_TIMER_APP_RDDT_TIMER_RESET, - U300_TIMER_APP_VBASE + U300_TIMER_APP_RDDT); + u300_timer_base + U300_TIMER_APP_RDDT); writel(U300_TIMER_APP_DDDT_TIMER_DISABLE, - U300_TIMER_APP_VBASE + U300_TIMER_APP_DDDT); + u300_timer_base + U300_TIMER_APP_DDDT); /* Reset the General Purpose timer 1. */ writel(U300_TIMER_APP_RGPT1_TIMER_RESET, - U300_TIMER_APP_VBASE + U300_TIMER_APP_RGPT1); + u300_timer_base + U300_TIMER_APP_RGPT1); /* Set up the IRQ handler */ - setup_irq(IRQ_U300_TIMER_APP_GP1, &u300_timer_irq); + setup_irq(irq, &u300_timer_irq); /* Reset the General Purpose timer 2 */ writel(U300_TIMER_APP_RGPT2_TIMER_RESET, - U300_TIMER_APP_VBASE + U300_TIMER_APP_RGPT2); + u300_timer_base + U300_TIMER_APP_RGPT2); /* Set this timer to run around forever */ - writel(0xFFFFFFFFU, U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT2TC); + writel(0xFFFFFFFFU, u300_timer_base + U300_TIMER_APP_GPT2TC); /* Set continuous mode so it wraps around */ writel(U300_TIMER_APP_SGPT2M_MODE_CONTINUOUS, - U300_TIMER_APP_VBASE + U300_TIMER_APP_SGPT2M); + u300_timer_base + U300_TIMER_APP_SGPT2M); /* Disable timer interrupts */ writel(U300_TIMER_APP_GPT2IE_IRQ_DISABLE, - U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT2IE); + u300_timer_base + U300_TIMER_APP_GPT2IE); /* Then enable the GP2 timer to use as a free running us counter */ writel(U300_TIMER_APP_EGPT2_TIMER_ENABLE, - U300_TIMER_APP_VBASE + U300_TIMER_APP_EGPT2); + u300_timer_base + U300_TIMER_APP_EGPT2); /* Use general purpose timer 2 as clock source */ - if (clocksource_mmio_init(U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT2CC, + if (clocksource_mmio_init(u300_timer_base + U300_TIMER_APP_GPT2CC, "GPT2", rate, 300, 32, clocksource_mmio_readl_up)) pr_err("timer: failed to initialize U300 clock source\n");