summaryrefslogtreecommitdiff
path: root/bsp/at91/at91sam9g45/drivers/board.c
blob: 4adf2d968954fed81a3ac71241ca2c5f870af914 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2011-01-13     weety      first version
 */

#include <rtthread.h>
#include <rthw.h>

#include "board.h"
#include <mmu.h>

/**
 * @addtogroup at91sam9g45
 */
/*@{*/
#if defined(__CC_ARM)
extern int Image$$ER_ZI$$ZI$$Limit;
#define HEAP_BEGIN  (&Image$$ER_ZI$$ZI$$Limit)
#elif (defined (__GNUC__))
extern unsigned char __bss_end;
#define HEAP_BEGIN  (&__bss_end)
#elif (defined (__ICCARM__))
#pragma section=".noinit"
#define HEAP_BEGIN  (__section_end(".noinit"))
#endif

#define HEAP_END    (((rt_uint32_t)HEAP_BEGIN & 0xF0000000) + 0x04000000)

extern void rt_hw_interrupt_init(void);
extern void rt_hw_clock_init(void);

extern void rt_hw_get_clock(void);
extern void rt_hw_set_dividor(rt_uint8_t hdivn, rt_uint8_t pdivn);
extern void rt_hw_set_clock(rt_uint8_t sdiv, rt_uint8_t pdiv, rt_uint8_t mdiv);
extern void rt_dbgu_isr(void);

#define SAM9G45_BLOCK_SIZE  0x10000000      // 256M
#define MMU_SECTION_SIZE    0x100000        // 1M
#define PERIPHERALS_ADDR            // 1M

#define SECTION_END(sa)     ((sa) + MMU_SECTION_SIZE - 1)   // sa: start address
#define BLOCK_END(ba)       ((ba) + SAM9G45_BLOCK_SIZE - 1) // ba: block address

static struct mem_desc at91_mem_desc[] = {  /* FIXME, hornby, to confirm MMU and memory */
      { 0x00000000,             0xFFFFFFFF , 0x00000000, RW_NCNB }, /* None cached for 4G memory */
    //{ 0x00000000, SECTION_END(0x00000000), 0x00000000, RW_CNB  }, /* TLB for ITCM, ITCM map to address zero, 32KB */
    //{ 0x00200000, SECTION_END(0x00200000), 0x00200000, RW_CNB  }, /* TLB for DTCM, 32KB */
    //{ 0x00300000, SECTION_END(0x00300000), 0x00300000, RW_CNB  }, /* TLB for internal RAM, 64KB, we use it as global variable area */
    //{ 0x00600000, SECTION_END(0x00600000), 0x00600000, RW_NCNB }, /* TLB for UDPHS(DMA) */
    //{ 0x00700000, SECTION_END(0x00700000), 0x00700000, RW_NCNB }, /* TLB for UHP OHCI */
    //{ 0x00800000, SECTION_END(0x00800000), 0x00800000, RW_NCNB }, /* TLB for UHP EHCI */
    //{ 0x30000000, 0x30000000+0x00100000-1, 0x30000000, RW_CB   }, /* 1M external SRAM for program code and stack */
    //{ 0x40000000,   BLOCK_END(0x40000000), 0x40000000, RW_NCNB }, /* 256M for nand-flash controller */
    //{ 0x60000000,   BLOCK_END(0x60000000), 0x60000000, RW_NCNB }, /* 256M for FPGA */
    //{ 0x70000000, 0x70000000+0x08000000-1, 0x70000000, RW_NCNB }, /* 128M for main DDR-SDRAM for print data */
      { 0x00000000, SECTION_END(0x00000000), 0x70000000, RW_CB   }, /* isr */
      { 0x70000000, 0x70000000+0x08000000-1, 0x70000000, RW_CB   }, /* 128M for main DDR-SDRAM for print data */
    //{ 0xFFF00000, SECTION_END(0xFFF00000), 0xFFF00000, RW_NCNB }, /* Internal Peripherals, 1MB */
};


#define PIT_CPIV(x)     ((x) & AT91C_PITC_CPIV)
#define PIT_PICNT(x)    (((x) & AT91C_PITC_PICNT) >> 20)

static rt_uint32_t pit_cycle;   /* write-once */
static rt_uint32_t pit_cnt;     /* access only w/system irq blocked */

/**
 * This function will handle rtos timer
 */
void rt_timer_handler(int vector, void *param)
{
#ifdef RT_USING_DBGU
    if (readl(AT91C_DBGU_CSR) & AT91C_US_RXRDY)
    {
        rt_dbgu_isr();
    }
#endif
    if (readl(AT91C_PITC_PISR) & AT91C_PITC_PITS)
    {
        unsigned nr_ticks;

        /* Get number of ticks performed before irq, and ack it */
        nr_ticks = PIT_PICNT(readl(AT91C_PITC_PIVR));
        while (nr_ticks--)
            rt_tick_increase();
    }
}

static void at91sam9g45_pit_reset(void)
{
    /* Disable timer and irqs */
    AT91C_BASE_PITC->PITC_PIMR = 0;

    /* Clear any pending interrupts, wait for PIT to stop counting */
    while (PIT_CPIV(readl(AT91C_PITC_PIVR)) != 0)
        ;

    /* Start PIT but don't enable IRQ */
    //AT91C_BASE_PITC->PITC_PIMR = (pit_cycle - 1) | AT91C_PITC_PITEN;
    pit_cnt += pit_cycle * PIT_PICNT(readl(AT91C_PITC_PIVR));
    AT91C_BASE_PITC->PITC_PIMR =
            (pit_cycle - 1) | AT91C_PITC_PITEN | AT91C_PITC_PITIEN;
    rt_kprintf("PIT_MR=0x%08x\n", readl(AT91C_PITC_PIMR));
}

/*
 * Set up both clocksource and clockevent support.
 */
static void at91sam9g45_pit_init(void)
{
    rt_uint32_t pit_rate;
    //rt_uint32_t   bits;

    /*
     * Use our actual MCK to figure out how many MCK/16 ticks per
     * 1/HZ period (instead of a compile-time constant LATCH).
     */
    pit_rate = clk_get_rate(clk_get("mck")) / 16;
    rt_kprintf("pit_rate=%dHZ\n", pit_rate);
    pit_cycle = (pit_rate + RT_TICK_PER_SECOND/2) / RT_TICK_PER_SECOND;

    /* Initialize and enable the timer */
    at91sam9g45_pit_reset();
}

/**
 * This function will init pit for system ticks
 */
void rt_hw_timer_init()
{
    at91sam9g45_pit_init();

    /* install interrupt handler */
    rt_hw_interrupt_install(AT91C_ID_SYS, rt_timer_handler,
                            RT_NULL, "system");
    rt_hw_interrupt_umask(AT91C_ID_SYS);
}

void at91_tc1_init()
{
    AT91C_BASE_PMC->PMC_PCER = 1<<AT91C_ID_TC;
    writel(AT91C_TCB_TC0XC0S_NONE | AT91C_TCB_TC1XC1S_NONE | AT91C_TCB_TC2XC2S_NONE, AT91C_TCB0_BMR);
    writel(AT91C_TC_CLKDIS, AT91C_TC0_CCR);
    writel(AT91C_TC_CLKS_TIMER_DIV4_CLOCK, AT91C_TC0_CMR);
    writel(0xffff, AT91C_TC0_CV);
}

#define BPS         115200  /* serial console port baudrate */

static void at91_usart_putc(char c)
{
    while (!(AT91C_BASE_DBGU->DBGU_CSR & AT91C_US_TXRDY))
        ;
    AT91C_BASE_DBGU->DBGU_THR = c;
}

/**
 * This function is used to display a string on console, normally, it's
 * invoked by rt_kprintf
 *
 * @param str the displayed string
 */
void rt_hw_console_output(const char* str)
{
    while (*str)
    {
        if (*str=='\n')
        {
            at91_usart_putc('\r');
        }

        at91_usart_putc(*str++);
    }
}

static void rt_hw_console_init(void)
{
    int div;
    int mode = 0;

    AT91C_BASE_DBGU->DBGU_CR = AT91C_US_RSTTX | AT91C_US_RSTRX |
           AT91C_US_RXDIS | AT91C_US_TXDIS;
    mode |= AT91C_US_USMODE_NORMAL | AT91C_US_CLKS_CLOCK |
           AT91C_US_CHMODE_NORMAL;
    mode |= AT91C_US_CHRL_8_BITS;
    mode |= AT91C_US_NBSTOP_1_BIT;
    mode |= AT91C_US_PAR_NONE;
    AT91C_BASE_DBGU->DBGU_MR = mode;
    div = (clk_get_rate(clk_get("mck")) / 16 + BPS/2) / BPS;
    AT91C_BASE_DBGU->DBGU_BRGR = div;
    AT91C_BASE_DBGU->DBGU_CR = AT91C_US_RXEN | AT91C_US_TXEN;
}


/**
 * This function will init at91sam9g45 board
 */
void rt_hw_board_init()
{
    /* initialize the system clock */
    rt_hw_clock_init();

    /* initialize console */
    rt_hw_console_init();

    /* initialize mmu */
    rt_hw_mmu_init(at91_mem_desc, sizeof(at91_mem_desc)/sizeof(at91_mem_desc[0]));

    /* initialize hardware interrupt */
    rt_hw_interrupt_init();

    /* initialize early device */
#ifdef RT_USING_COMPONENTS_INIT
    rt_components_board_init();
#endif

#if defined(RT_USING_CONSOLE) && defined(RT_USING_DEVICE)
    rt_console_set_device(RT_CONSOLE_DEVICE_NAME);
#endif
    /* initialize timer0 */
    rt_hw_timer_init();

/* initialize board */
#ifdef RT_USING_HEAP
    rt_system_heap_init((void *)HEAP_BEGIN, (void *)HEAP_END);
#endif
}

/*@}*/