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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a1b9f63 was a1b9f63, checked in by Jakub Jermar <jakub@…>, 7 years ago

Add alignment argument to km_map()

km_map() currently always applies alignment requirement equal to the
size of the mapped region. Most of the time, the natural alignment is
unnecessarily strong and especially on 32-bit systems may contribute to
km_map() failures for regions with size in the order of several hundred
megabytes.

This change adds an extra argument to km_map() which allows the caller
to indicate the desired alignment. The old behaviour can be specified
by passing KM_NATURAL_ALIGNMENT as alignment.

This change only adds the alignment argument, but does not change the
alignment requirement anywhere.

  • Property mode set to 100644
File size: 5.0 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 <assert.h>
37#include <genarch/drivers/am335x/timer.h>
38#include <mm/km.h>
39#include <errno.h>
40
41typedef enum {
42 REG_TCLR = 0x00,
43 REG_TCRR = 0x01,
44 REG_TLDR = 0x02,
45 REG_TTGR = 0x04
46} timer_reg_t;
47
48typedef struct timer_regs_mmap {
49 uintptr_t base;
50 size_t size;
51} timer_regs_mmap_t;
52
53static const timer_regs_mmap_t regs_map[TIMERS_MAX] = {
54 { .base = AM335x_DMTIMER0_BASE_ADDRESS, .size = AM335x_DMTIMER0_SIZE },
55 { 0, 0 }, /* DMTIMER1 is not supported by this driver */
56 { .base = AM335x_DMTIMER2_BASE_ADDRESS, .size = AM335x_DMTIMER2_SIZE },
57 { .base = AM335x_DMTIMER3_BASE_ADDRESS, .size = AM335x_DMTIMER3_SIZE },
58 { .base = AM335x_DMTIMER4_BASE_ADDRESS, .size = AM335x_DMTIMER4_SIZE },
59 { .base = AM335x_DMTIMER5_BASE_ADDRESS, .size = AM335x_DMTIMER5_SIZE },
60 { .base = AM335x_DMTIMER6_BASE_ADDRESS, .size = AM335x_DMTIMER6_SIZE },
61 { .base = AM335x_DMTIMER7_BASE_ADDRESS, .size = AM335x_DMTIMER7_SIZE },
62};
63
64static void
65write_register_posted(am335x_timer_t *timer, timer_reg_t reg, uint32_t value)
66{
67 am335x_timer_regs_t *regs = timer->regs;
68
69 while (regs->twps & reg)
70 ;
71
72 switch (reg) {
73 default:
74 return;
75 case REG_TCLR:
76 regs->tclr = value;
77 break;
78 case REG_TCRR:
79 regs->tcrr = value;
80 break;
81 case REG_TLDR:
82 regs->tldr = value;
83 break;
84 }
85}
86
87errno_t
88am335x_timer_init(am335x_timer_t *timer, am335x_timer_id_t id, unsigned hz,
89 unsigned srcclk_hz)
90{
91 uintptr_t base_addr;
92 size_t size;
93
94 assert(id < TIMERS_MAX);
95 assert(timer != NULL);
96
97 if (id == DMTIMER1_1MS)
98 return ENOTSUP; /* Not supported yet */
99
100 base_addr = regs_map[id].base;
101 size = regs_map[id].size;
102
103 timer->regs = (void *) km_map(base_addr, size, KM_NATURAL_ALIGNMENT,
104 PAGE_NOT_CACHEABLE);
105 assert(timer->regs != NULL);
106
107 timer->id = id;
108
109 am335x_timer_regs_t *regs = timer->regs;
110
111 /* Enable the posted mode of operation */
112 regs->tsicr |= AM335x_TIMER_TSICR_POSTED_FLAG;
113
114 /* Stop the timer */
115 am335x_timer_stop(timer);
116
117 /* Perform a soft reset */
118 am335x_timer_reset(timer);
119
120 unsigned tclr = regs->tclr;
121
122 /* Disable compare mode */
123 tclr &= ~AM335x_TIMER_TCLR_CE_FLAG;
124
125 /* Enable auto-reload mode */
126 tclr |= AM335x_TIMER_TCLR_AR_FLAG;
127
128 write_register_posted(timer, REG_TCLR, tclr);
129
130 /* Disable the emulation mode */
131 regs->tiocp_cfg |= AM335x_TIMER_TIOCPCFG_EMUFREE_FLAG;
132
133 unsigned const count = 0xFFFFFFFF - (srcclk_hz / hz + 1);
134 write_register_posted(timer, REG_TCRR, count);
135 write_register_posted(timer, REG_TLDR, count);
136
137 return EOK;
138}
139
140void
141am335x_timer_intr_ack(am335x_timer_t *timer)
142{
143 /* Clear pending OVF event */
144 timer->regs->irqstatus |= AM335x_TIMER_IRQSTATUS_OVF_FLAG;
145}
146
147void
148am335x_timer_reset(am335x_timer_t *timer)
149{
150 /* Initiate soft reset */
151 timer->regs->tiocp_cfg |= AM335x_TIMER_TIOCPCFG_SOFTRESET_FLAG;
152 /* Wait until the reset is done */
153 while (timer->regs->tiocp_cfg & AM335x_TIMER_TIOCPCFG_SOFTRESET_FLAG)
154 ;
155}
156
157void
158am335x_timer_stop(am335x_timer_t *timer)
159{
160 /* Disable the interrupt */
161 timer->regs->irqenable_clr |= AM335x_TIMER_IRQENABLE_CLR_OVF_FLAG;
162 timer->regs->irqwakeen &= ~AM335x_TIMER_IRQWAKEEN_OVF_FLAG;
163 /* Stop the timer */
164 write_register_posted(timer, REG_TCLR,
165 timer->regs->tclr & ~AM335x_TIMER_TCLR_ST_FLAG);
166}
167
168void
169am335x_timer_start(am335x_timer_t *timer)
170{
171 /* Enable the interrupt */
172 timer->regs->irqenable_set |= AM335x_TIMER_IRQENABLE_SET_OVF_FLAG;
173 timer->regs->irqwakeen |= AM335x_TIMER_IRQWAKEEN_OVF_FLAG;
174 /* Start the clock */
175 write_register_posted(timer, REG_TCLR,
176 timer->regs->tclr | AM335x_TIMER_TCLR_ST_FLAG);
177}
178
179/**
180 * @}
181 */
182
Note: See TracBrowser for help on using the repository browser.