blob: 5a19d5293c5dbc64aaa02fd2a454775b5343b02b (
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
|
// Main starting point for SAM3/SAM4 boards
//
// Copyright (C) 2016-2019 Kevin O'Connor <kevin@koconnor.net>
//
// This file may be distributed under the terms of the GNU GPLv3 license.
#include "board/armcm_boot.h" // armcm_main
#include "board/irq.h" // irq_disable
#include "board/usb_cdc.h" // usb_request_bootloader
#include "command.h" // DECL_COMMAND_FLAGS
#include "internal.h" // WDT
#include "sched.h" // sched_main
#define FREQ_PERIPH_DIV (CONFIG_MACH_SAME70 ? 2 : 1)
#define FREQ_PERIPH (CONFIG_CLOCK_FREQ / FREQ_PERIPH_DIV)
/****************************************************************
* watchdog handler
****************************************************************/
void
watchdog_reset(void)
{
WDT->WDT_CR = 0xA5000001;
}
DECL_TASK(watchdog_reset);
void
watchdog_init(void)
{
uint32_t timeout = 500 * 32768 / 128 / 1000; // 500ms timeout
WDT->WDT_MR = WDT_MR_WDRSTEN | WDT_MR_WDV(timeout) | WDT_MR_WDD(timeout);
}
DECL_INIT(watchdog_init);
/****************************************************************
* Peripheral clocks
****************************************************************/
// Check if a peripheral clock has been enabled
int
is_enabled_pclock(uint32_t id)
{
if (id < 32)
return !!(PMC->PMC_PCSR0 & (1 << id));
else
return !!(PMC->PMC_PCSR1 & (1 << (id - 32)));
}
// Enable a peripheral clock
void
enable_pclock(uint32_t id)
{
if (id < 32)
PMC->PMC_PCER0 = 1 << id;
else
PMC->PMC_PCER1 = 1 << (id - 32);
}
// Return the frequency of the given peripheral clock
uint32_t
get_pclock_frequency(uint32_t id)
{
return FREQ_PERIPH;
}
/****************************************************************
* Resets
****************************************************************/
#if CONFIG_MACH_SAME70
#define RST_PARAMS ((0xA5 << RSTC_CR_KEY_Pos) | RSTC_CR_PROCRST)
#else
#define RST_PARAMS ((0xA5 << RSTC_CR_KEY_Pos) | RSTC_CR_PROCRST \
| RSTC_CR_PERRST)
#endif
void
command_reset(uint32_t *args)
{
irq_disable();
RSTC->RSTC_CR = RST_PARAMS;
for (;;)
;
}
DECL_COMMAND_FLAGS(command_reset, HF_IN_SHUTDOWN, "reset");
#if CONFIG_MACH_SAM3X || CONFIG_MACH_SAM4S
#define EFC_HW EFC0
#elif CONFIG_MACH_SAM4E || CONFIG_MACH_SAME70
#define EFC_HW EFC
#endif
void noinline __aligned(16) // align for predictable flash code access
usb_request_bootloader(void)
{
irq_disable();
// Request boot from ROM (instead of boot from flash)
while ((EFC_HW->EEFC_FSR & EEFC_FSR_FRDY) == 0)
;
EFC_HW->EEFC_FCR = (EEFC_FCR_FCMD_CGPB | EEFC_FCR_FARG(1)
| EEFC_FCR_FKEY_PASSWD);
while ((EFC_HW->EEFC_FSR & EEFC_FSR_FRDY) == 0)
;
// Reboot
RSTC->RSTC_CR = RST_PARAMS;
for (;;)
;
}
/****************************************************************
* Startup
****************************************************************/
static void
matrix_init(void)
{
// The ATSAM sram is in a "no default master" state at reset
// (despite the specs). That typically adds 1 wait cycle to every
// memory access. Set it to "last access master" to avoid that.
MATRIX->MATRIX_SCFG[0] = (MATRIX_SCFG_SLOT_CYCLE(64)
| MATRIX_SCFG_DEFMSTR_TYPE(1));
}
// Main entry point - called from armcm_boot.c:ResetHandler()
void
armcm_main(void)
{
SystemInit();
matrix_init();
sched_main();
}
|