diff options
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/target/mips/ingenic_x1000/boot-x1000.c | 146 | ||||
-rw-r--r-- | firmware/target/mips/ingenic_x1000/boot-x1000.h | 6 |
2 files changed, 151 insertions, 1 deletions
diff --git a/firmware/target/mips/ingenic_x1000/boot-x1000.c b/firmware/target/mips/ingenic_x1000/boot-x1000.c index 3ba060ffc4..feb67994b7 100644 --- a/firmware/target/mips/ingenic_x1000/boot-x1000.c +++ b/firmware/target/mips/ingenic_x1000/boot-x1000.c | |||
@@ -19,8 +19,14 @@ | |||
19 | * | 19 | * |
20 | ****************************************************************************/ | 20 | ****************************************************************************/ |
21 | 21 | ||
22 | #include "boot-x1000.h" | ||
23 | #include "system.h" | 22 | #include "system.h" |
23 | #include "boot-x1000.h" | ||
24 | #include "nand-x1000.h" | ||
25 | #include "gpio-x1000.h" | ||
26 | #include "clk-x1000.h" | ||
27 | #include "x1000/cpm.h" | ||
28 | #include "x1000/lcd.h" | ||
29 | #include "x1000/uart.h" | ||
24 | #include <string.h> | 30 | #include <string.h> |
25 | 31 | ||
26 | #define HDR_BEGIN 128 /* header must begin within this many bytes */ | 32 | #define HDR_BEGIN 128 /* header must begin within this many bytes */ |
@@ -136,3 +142,141 @@ void rolo_restart(const unsigned char* source, unsigned char* dest, int length) | |||
136 | (void)dest; | 142 | (void)dest; |
137 | x1000_boot_rockbox(source, length); | 143 | x1000_boot_rockbox(source, length); |
138 | } | 144 | } |
145 | |||
146 | void x1000_dualboot_cleanup(void) | ||
147 | { | ||
148 | #ifdef SHANLING_Q1 | ||
149 | /* hack for the Q1 since OF kernels don't reset this bit, | ||
150 | * leading to garbled graphics. */ | ||
151 | if(!jz_readf(CPM_CLKGR, LCD)) { | ||
152 | jz_writef(LCD_CTRL, BEDN(0)); | ||
153 | } | ||
154 | #endif | ||
155 | |||
156 | /* clear USB PHY voodoo bits, not all kernels use them */ | ||
157 | jz_writef(CPM_OPCR, GATE_USBPHY_CLK(0)); | ||
158 | jz_writef(CPM_USBCDR, PHY_GATE(0)); | ||
159 | |||
160 | #if defined(FIIO_M3K) || defined(EROS_QN) | ||
161 | /* | ||
162 | * Need to bring up MPLL before booting Linux | ||
163 | * (Doesn't apply to Q1 since it sticks with the default Ingenic config) | ||
164 | */ | ||
165 | |||
166 | /* 24 MHz * 25 = 600 MHz */ | ||
167 | jz_writef(CPM_MPCR, BS(1), PLLM(25 - 1), PLLN(0), PLLOD(0), ENABLE(1)); | ||
168 | while(jz_readf(CPM_MPCR, ON) == 0); | ||
169 | |||
170 | /* 600 MHz / 3 = 200 MHz */ | ||
171 | clk_set_ddr(X1000_CLK_MPLL, 3); | ||
172 | |||
173 | clk_set_ccr_mux(CLKMUX_SCLK_A(APLL) | | ||
174 | CLKMUX_CPU(SCLK_A) | | ||
175 | CLKMUX_AHB0(MPLL) | | ||
176 | CLKMUX_AHB2(MPLL)); | ||
177 | clk_set_ccr_div(CLKDIV_CPU(1) | /* 1008 MHz */ | ||
178 | CLKDIV_L2(2) | /* 504 MHz */ | ||
179 | CLKDIV_AHB0(3) | /* 200 MHz */ | ||
180 | CLKDIV_AHB2(3) | /* 200 MHz */ | ||
181 | CLKDIV_PCLK(6)); /* 100 MHz */ | ||
182 | #endif | ||
183 | } | ||
184 | |||
185 | void x1000_dualboot_init_clocktree(void) | ||
186 | { | ||
187 | /* Make sure these are gated to match the OF behavior. */ | ||
188 | jz_writef(CPM_CLKGR, PCM(1), MAC(1), LCD(1), MSC0(1), MSC1(1), OTG(1), CIM(1)); | ||
189 | |||
190 | /* Set clock sources, and make sure every clock starts out stopped */ | ||
191 | jz_writef(CPM_I2SCDR, CS_V(EXCLK)); | ||
192 | jz_writef(CPM_PCMCDR, CS_V(EXCLK)); | ||
193 | |||
194 | jz_writef(CPM_MACCDR, CLKSRC_V(MPLL), CE(1), STOP(1), CLKDIV(0xfe)); | ||
195 | while(jz_readf(CPM_MACCDR, BUSY)); | ||
196 | |||
197 | jz_writef(CPM_LPCDR, CLKSRC_V(MPLL), CE(1), STOP(1), CLKDIV(0xfe)); | ||
198 | while(jz_readf(CPM_LPCDR, BUSY)); | ||
199 | |||
200 | jz_writef(CPM_MSC0CDR, CLKSRC_V(MPLL), CE(1), STOP(1), CLKDIV(0xfe)); | ||
201 | while(jz_readf(CPM_MSC0CDR, BUSY)); | ||
202 | |||
203 | jz_writef(CPM_MSC1CDR, CE(1), STOP(1), CLKDIV(0xfe)); | ||
204 | while(jz_readf(CPM_MSC1CDR, BUSY)); | ||
205 | |||
206 | jz_writef(CPM_CIMCDR, CLKSRC_V(MPLL), CE(1), STOP(1), CLKDIV(0xfe)); | ||
207 | while(jz_readf(CPM_CIMCDR, BUSY)); | ||
208 | |||
209 | jz_writef(CPM_USBCDR, CLKSRC_V(EXCLK), CE(1), STOP(1)); | ||
210 | while(jz_readf(CPM_USBCDR, BUSY)); | ||
211 | } | ||
212 | |||
213 | void x1000_dualboot_init_uart2(void) | ||
214 | { | ||
215 | /* Ungate the clock and select UART2 device function */ | ||
216 | jz_writef(CPM_CLKGR, UART2(0)); | ||
217 | gpioz_configure(GPIO_C, 3 << 30, GPIOF_DEVICE(1)); | ||
218 | |||
219 | /* Disable all interrupts */ | ||
220 | jz_write(UART_UIER(2), 0); | ||
221 | |||
222 | /* FIFO configuration */ | ||
223 | jz_overwritef(UART_UFCR(2), | ||
224 | RDTR(3), /* FIFO trigger level = 60? */ | ||
225 | UME(0), /* UART module disable */ | ||
226 | DME(1), /* DMA mode enable? */ | ||
227 | TFRT(1), /* transmit FIFO reset */ | ||
228 | RFRT(1), /* receive FIFO reset */ | ||
229 | FME(1)); /* FIFO mode enable */ | ||
230 | |||
231 | /* IR mode configuration */ | ||
232 | jz_overwritef(UART_ISR(2), | ||
233 | RDPL(1), /* Zero is negative pulse for receive */ | ||
234 | TDPL(1), /* ... and for transmit */ | ||
235 | XMODE(1), /* Pulse width 1.6us */ | ||
236 | RCVEIR(0), /* Disable IR for recieve */ | ||
237 | XMITIR(0)); /* ... and for transmit */ | ||
238 | |||
239 | /* Line configuration */ | ||
240 | jz_overwritef(UART_ULCR(2), DLAB(0), | ||
241 | WLS_V(8BITS), /* 8 bit words */ | ||
242 | SBLS_V(1_STOP_BIT), /* 1 stop bit */ | ||
243 | PARE(0), /* no parity */ | ||
244 | SBK(0)); /* don't set break */ | ||
245 | |||
246 | /* Set the baud rate... not too sure how this works. (Docs unclear!) */ | ||
247 | const unsigned divisor = 0x0004; | ||
248 | jz_writef(UART_ULCR(2), DLAB(1)); | ||
249 | jz_write(UART_UDLHR(2), (divisor >> 8) & 0xff); | ||
250 | jz_write(UART_UDLLR(2), divisor & 0xff); | ||
251 | jz_write(UART_UMR(2), 16); | ||
252 | jz_write(UART_UACR(2), 0); | ||
253 | jz_writef(UART_ULCR(2), DLAB(0)); | ||
254 | |||
255 | /* Enable UART */ | ||
256 | jz_overwritef(UART_UFCR(2), | ||
257 | RDTR(0), /* FIFO trigger level = 1 */ | ||
258 | DME(0), /* DMA mode disable */ | ||
259 | UME(1), /* UART module enable */ | ||
260 | TFRT(1), /* transmit FIFO reset */ | ||
261 | RFRT(1), /* receive FIFO reset */ | ||
262 | FME(1)); /* FIFO mode enable */ | ||
263 | } | ||
264 | |||
265 | int x1000_dualboot_load_pdma_fw(void) | ||
266 | { | ||
267 | nand_drv* n = nand_init(); | ||
268 | nand_lock(n); | ||
269 | |||
270 | int ret = nand_open(n); | ||
271 | if(ret != NAND_SUCCESS) | ||
272 | goto err_unlock; | ||
273 | |||
274 | /* NOTE: hardcoded address is used by all current targets */ | ||
275 | jz_writef(CPM_CLKGR, PDMA(0)); | ||
276 | ret = nand_read_bytes(n, 0x4000, 0x2000, (void*)0xb3422000); | ||
277 | |||
278 | nand_close(n); | ||
279 | err_unlock: | ||
280 | nand_unlock(n); | ||
281 | return ret; | ||
282 | } | ||
diff --git a/firmware/target/mips/ingenic_x1000/boot-x1000.h b/firmware/target/mips/ingenic_x1000/boot-x1000.h index 9faba649b5..fa918a3ead 100644 --- a/firmware/target/mips/ingenic_x1000/boot-x1000.h +++ b/firmware/target/mips/ingenic_x1000/boot-x1000.h | |||
@@ -51,6 +51,12 @@ void x1000_boot_linux(const void* source, size_t length, | |||
51 | void* load, void* entry, const char* args) | 51 | void* load, void* entry, const char* args) |
52 | __attribute__((section(".icode"))); | 52 | __attribute__((section(".icode"))); |
53 | 53 | ||
54 | /* dual boot support code */ | ||
55 | void x1000_dualboot_cleanup(void); | ||
56 | void x1000_dualboot_init_clocktree(void); | ||
57 | void x1000_dualboot_init_uart2(void); | ||
58 | int x1000_dualboot_load_pdma_fw(void); | ||
59 | |||
54 | /* Note: these functions are inlined to minimize SPL code size. | 60 | /* Note: these functions are inlined to minimize SPL code size. |
55 | * They are private to the X1000 early boot code anyway... */ | 61 | * They are private to the X1000 early boot code anyway... */ |
56 | 62 | ||