diff options
Diffstat (limited to 'utils/hwstub/stub/rk27xx/target.c')
-rw-r--r-- | utils/hwstub/stub/rk27xx/target.c | 172 |
1 files changed, 172 insertions, 0 deletions
diff --git a/utils/hwstub/stub/rk27xx/target.c b/utils/hwstub/stub/rk27xx/target.c new file mode 100644 index 0000000000..f9efccaef0 --- /dev/null +++ b/utils/hwstub/stub/rk27xx/target.c | |||
@@ -0,0 +1,172 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * | ||
9 | * Copyright (C) 2013 by Marcin Bukat | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License | ||
13 | * as published by the Free Software Foundation; either version 2 | ||
14 | * of the License, or (at your option) any later version. | ||
15 | * | ||
16 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
17 | * KIND, either express or implied. | ||
18 | * | ||
19 | ****************************************************************************/ | ||
20 | #include "stddef.h" | ||
21 | #include "target.h" | ||
22 | #include "system.h" | ||
23 | #include "logf.h" | ||
24 | #include "rk27xx.h" | ||
25 | |||
26 | #define HZ 1000000 | ||
27 | |||
28 | enum rk27xx_family_t | ||
29 | { | ||
30 | UNKNOWN, | ||
31 | REV_A, | ||
32 | REV_B, | ||
33 | }; | ||
34 | |||
35 | static enum rk27xx_family_t g_rk27xx_family = UNKNOWN; | ||
36 | static int g_atexit = HWSTUB_ATEXIT_OFF; | ||
37 | |||
38 | static void _enable_irq(void) | ||
39 | { | ||
40 | asm volatile ("mrs r0, cpsr\n" | ||
41 | "bic r0, r0, #0x80\n" | ||
42 | "msr cpsr_c, r0\n" | ||
43 | ); | ||
44 | } | ||
45 | |||
46 | static void power_off(void) | ||
47 | { | ||
48 | GPIO_PCCON &= ~(1<<0); | ||
49 | while(1); | ||
50 | } | ||
51 | |||
52 | static void rk27xx_reset(void) | ||
53 | { | ||
54 | /* use Watchdog to reset */ | ||
55 | SCU_CLKCFG &= ~CLKCFG_WDT; | ||
56 | WDTLR = 1; | ||
57 | WDTCON = (1<<4) | (1<<3); | ||
58 | |||
59 | /* Wait for reboot to kick in */ | ||
60 | while(1); | ||
61 | } | ||
62 | |||
63 | /* us may be at most 2^31/200 (~10 seconds) for 200MHz max cpu freq */ | ||
64 | void target_udelay(int us) | ||
65 | { | ||
66 | unsigned cycles_per_us; | ||
67 | unsigned delay; | ||
68 | |||
69 | cycles_per_us = (200000000 + 999999) / 1000000; | ||
70 | |||
71 | delay = (us * cycles_per_us) / 5; | ||
72 | |||
73 | asm volatile( | ||
74 | "1: subs %0, %0, #1 \n" /* 1 cycle */ | ||
75 | " nop \n" /* 1 cycle */ | ||
76 | " bne 1b \n" /* 3 cycles */ | ||
77 | : : "r"(delay) | ||
78 | ); | ||
79 | } | ||
80 | |||
81 | void target_mdelay(int ms) | ||
82 | { | ||
83 | return target_udelay(ms * 1000); | ||
84 | } | ||
85 | |||
86 | void target_init(void) | ||
87 | { | ||
88 | /* ungate all clocks */ | ||
89 | SCU_CLKCFG = 0; | ||
90 | |||
91 | /* keep act line */ | ||
92 | GPIO_PCDR |= (1<<0); | ||
93 | GPIO_PCCON |= (1<<0); | ||
94 | |||
95 | /* disable watchdog */ | ||
96 | WDTCON &= ~(1<<3); | ||
97 | |||
98 | /* enable UDC interrupt */ | ||
99 | INTC_IMR = (1<<16); | ||
100 | INTC_IECR = (1<<16); | ||
101 | |||
102 | EN_INT = EN_SUSP_INTR | /* Enable Suspend Interrupt */ | ||
103 | EN_RESUME_INTR | /* Enable Resume Interrupt */ | ||
104 | EN_USBRST_INTR | /* Enable USB Reset Interrupt */ | ||
105 | EN_OUT0_INTR | /* Enable OUT Token receive Interrupt EP0 */ | ||
106 | EN_IN0_INTR | /* Enable IN Token transmits Interrupt EP0 */ | ||
107 | EN_SETUP_INTR; /* Enable SETUP Packet Receive Interrupt */ | ||
108 | |||
109 | /* 6. configure INTCON */ | ||
110 | INTCON = UDC_INTHIGH_ACT | /* interrupt high active */ | ||
111 | UDC_INTEN; /* enable EP0 interrupts */ | ||
112 | |||
113 | /* enable irq */ | ||
114 | _enable_irq(); | ||
115 | |||
116 | /* detect revision */ | ||
117 | uint32_t rk27xx_id = SCU_ID; | ||
118 | |||
119 | if(rk27xx_id == 0xa1000604) | ||
120 | { | ||
121 | logf("identified rk27xx REV_A \n"); | ||
122 | g_rk27xx_family = REV_A; | ||
123 | } | ||
124 | else if(rk27xx_id == 0xa100027b) | ||
125 | { | ||
126 | logf("identified rk27xx REV_B \n"); | ||
127 | g_rk27xx_family = REV_B; | ||
128 | } | ||
129 | else | ||
130 | { | ||
131 | logf("unknown rk27xx revision \n"); | ||
132 | } | ||
133 | } | ||
134 | |||
135 | static struct usb_resp_info_target_t g_target = | ||
136 | { | ||
137 | .id = HWSTUB_TARGET_RK27, | ||
138 | .name = "Rockchip RK27XX" | ||
139 | }; | ||
140 | |||
141 | int target_get_info(int info, void **buffer) | ||
142 | { | ||
143 | if(info == HWSTUB_INFO_TARGET) | ||
144 | { | ||
145 | *buffer = &g_target; | ||
146 | return sizeof(g_target); | ||
147 | } | ||
148 | else | ||
149 | return -1; | ||
150 | } | ||
151 | |||
152 | int target_atexit(int method) | ||
153 | { | ||
154 | g_atexit = method; | ||
155 | return 0; | ||
156 | } | ||
157 | |||
158 | void target_exit(void) | ||
159 | { | ||
160 | switch(g_atexit) | ||
161 | { | ||
162 | case HWSTUB_ATEXIT_OFF: | ||
163 | power_off(); | ||
164 | // fallthrough in case of return | ||
165 | case HWSTUB_ATEXIT_REBOOT: | ||
166 | rk27xx_reset(); | ||
167 | // fallthrough in case of return | ||
168 | case HWSTUB_ATEXIT_NOP: | ||
169 | default: | ||
170 | return; | ||
171 | } | ||
172 | } | ||