source: mainline/kernel/genarch/src/drivers/am335x/timer.c@ 9c56996

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 9c56996 was 9c56996, checked in by Maurizio Lombardi <m.lombardi85@…>, 12 years ago

Add some sanity checks

  • Property mode set to 100644
File size: 5.1 KB
Line 
1/*
2 * Copyright (c) 2012 Maurizio Lombardi
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28/** @addtogroup genarch
29 * @{
30 */
31/**
32 * @file
33 * @brief Texas Instruments AM335x timer driver.
34 */
35
36#include <genarch/drivers/am335x/timer.h>
37#include <mm/km.h>
38#include <errno.h>
39
40typedef enum {
41 REG_TCLR = 0x00,
42 REG_TCRR = 0x01,
43 REG_TLDR = 0x02,
44 REG_TTGR = 0x04
45} timer_reg_t;
46
47typedef struct timer_regs_mmap {
48 uintptr_t base;
49 size_t size;
50} timer_regs_mmap_t;
51
52static const timer_regs_mmap_t regs_map[TIMERS_MAX] = {
53 { .base = AM335x_DMTIMER0_BASE_ADDRESS, .size = AM335x_DMTIMER0_SIZE },
54 {0, 0}, /* DMTIMER1 is not supported by this driver */
55 { .base = AM335x_DMTIMER2_BASE_ADDRESS, .size = AM335x_DMTIMER2_SIZE },
56 { .base = AM335x_DMTIMER3_BASE_ADDRESS, .size = AM335x_DMTIMER3_SIZE },
57 { .base = AM335x_DMTIMER4_BASE_ADDRESS, .size = AM335x_DMTIMER4_SIZE },
58 { .base = AM335x_DMTIMER5_BASE_ADDRESS, .size = AM335x_DMTIMER5_SIZE },
59 { .base = AM335x_DMTIMER6_BASE_ADDRESS, .size = AM335x_DMTIMER6_SIZE },
60 { .base = AM335x_DMTIMER7_BASE_ADDRESS, .size = AM335x_DMTIMER7_SIZE },
61};
62
63static void
64write_register_posted(am335x_timer_t *timer, timer_reg_t reg, uint32_t value)
65{
66 am335x_timer_regs_t *regs = timer->regs;
67
68 while (regs->twps & reg);
69
70 switch (reg) {
71 default:
72 return;
73 case REG_TCLR:
74 regs->tclr = value;
75 break;
76 case REG_TCRR:
77 regs->tcrr = value;
78 break;
79 case REG_TLDR:
80 regs->tldr = value;
81 break;
82 }
83}
84
85int
86am335x_timer_init(am335x_timer_t *timer, am335x_timer_id_t id, unsigned hz,
87 unsigned srcclk_hz)
88{
89 uintptr_t base_addr;
90 size_t size;
91
92 ASSERT(id < TIMERS_MAX);
93 ASSERT(timer != NULL);
94
95 if (id == DMTIMER1_1MS)
96 return ENOTSUP; /* Not supported yet */
97
98 base_addr = regs_map[id].base;
99 size = regs_map[id].size;
100
101 timer->regs = (void *) km_map(base_addr, size, PAGE_NOT_CACHEABLE);
102 ASSERT(timer->regs != NULL);
103
104 timer->id = id;
105
106 am335x_timer_regs_t *regs = timer->regs;
107
108 /* Enable the posted mode of operation */
109 regs->tsicr |= AM335x_TIMER_TSICR_POSTED_FLAG;
110
111 /* Stop the timer */
112 am335x_timer_stop(timer);
113
114 /* Perform a soft reset */
115 am335x_timer_reset(timer);
116
117 unsigned tclr = regs->tclr;
118
119 /* Disable compare mode */
120 tclr &= ~AM335x_TIMER_TCLR_CE_FLAG;
121 /* Enable the prescaler, divisor = 2 */
122 tclr |= AM335x_TIMER_TCLR_PRE_FLAG;
123 tclr &= ~(AM335x_TIMER_TCLR_PTV_MASK << AM335x_TIMER_TCLR_PTV_SHIFT);
124 /* Enable auto-reload mode */
125 tclr |= AM335x_TIMER_TCLR_AR_FLAG;
126
127 write_register_posted(timer, REG_TCLR, tclr);
128
129 /* Disable the emulation mode */
130 regs->tiocp_cfg |= AM335x_TIMER_TIOCPCFG_EMUFREE_FLAG;
131
132 unsigned const count = 0xFFFFFFFF - (srcclk_hz / hz + 1);
133 write_register_posted(timer, REG_TCRR, count);
134 write_register_posted(timer, REG_TLDR, count);
135
136 return EOK;
137}
138
139void
140am335x_timer_intr_ack(am335x_timer_t *timer)
141{
142 /* Clear pending OVF event */
143 timer->regs->irqstatus |= AM335x_TIMER_IRQSTATUS_OVF_FLAG;
144}
145
146void
147am335x_timer_reset(am335x_timer_t *timer)
148{
149 /* Initiate soft reset */
150 timer->regs->tiocp_cfg |= AM335x_TIMER_TIOCPCFG_SOFTRESET_FLAG;
151 /* Wait until the reset is done */
152 while (timer->regs->tiocp_cfg & AM335x_TIMER_TIOCPCFG_SOFTRESET_FLAG);
153}
154
155void
156am335x_timer_stop(am335x_timer_t *timer)
157{
158 /* Disable the interrupt */
159 timer->regs->irqenable_clr |= AM335x_TIMER_IRQENABLE_CLR_OVF_FLAG;
160 timer->regs->irqwakeen &= ~AM335x_TIMER_IRQWAKEEN_OVF_FLAG;
161 /* Stop the timer */
162 write_register_posted(timer, REG_TCLR,
163 timer->regs->tclr & ~AM335x_TIMER_TCLR_ST_FLAG);
164}
165
166void
167am335x_timer_start(am335x_timer_t *timer)
168{
169 /* Enable the interrupt */
170 timer->regs->irqenable_set |= AM335x_TIMER_IRQENABLE_SET_OVF_FLAG;
171 timer->regs->irqwakeen |= AM335x_TIMER_IRQWAKEEN_OVF_FLAG;
172 /* Start the clock */
173 write_register_posted(timer, REG_TCLR,
174 timer->regs->tclr | AM335x_TIMER_TCLR_ST_FLAG);
175}
176
177/**
178 * @}
179 */
180
Note: See TracBrowser for help on using the repository browser.