Add BSP support for F1C100s
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* exception.c
|
||||
*
|
||||
* Copyright(c) 2007-2018 Jianjun Jiang <8192542@qq.com>
|
||||
* Official site: http://xboot.org
|
||||
* Mobile phone: +86-18665388956
|
||||
* QQ: 8192542
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <arm32.h>
|
||||
#include <string.h>
|
||||
|
||||
static void show_regs(struct arm_regs_t * regs)
|
||||
{
|
||||
int i;
|
||||
|
||||
printf("pc : [<%08lx>] lr : [<%08lx>] cpsr: %08lx\r\n", regs->pc, regs->lr, regs->cpsr);
|
||||
printf("sp : %08lx\r\n", regs->sp);
|
||||
for(i = 12; i >= 0; i--)
|
||||
{
|
||||
printf("r%-2d: %08lx ", i, regs->r[i]);
|
||||
if(i % 2 == 0)
|
||||
printf("\r\n");
|
||||
}
|
||||
printf("\r\n");
|
||||
}
|
||||
|
||||
void arm32_do_undefined_instruction(struct arm_regs_t * regs)
|
||||
{
|
||||
//gdbserver_handle_exception(regs);
|
||||
}
|
||||
|
||||
void arm32_do_software_interrupt(struct arm_regs_t * regs)
|
||||
{
|
||||
show_regs(regs);
|
||||
regs->pc += 4;
|
||||
}
|
||||
|
||||
void arm32_do_prefetch_abort(struct arm_regs_t * regs)
|
||||
{
|
||||
show_regs(regs);
|
||||
regs->pc += 4;
|
||||
}
|
||||
|
||||
void arm32_do_data_abort(struct arm_regs_t * regs)
|
||||
{
|
||||
show_regs(regs);
|
||||
regs->pc += 4;
|
||||
}
|
||||
|
||||
_Noreturn void __fatal_error(const char *msg) {
|
||||
printf("%s\n", msg);
|
||||
while (1);
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
_Noreturn void __assert_func(const char *file, int line, const char *func, const char *expr) {
|
||||
//printf("Assertion '%s' failed, at file %s:%d\n", expr, file, line);
|
||||
__fatal_error("Assertion failed");
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,173 @@
|
||||
// Originally designed by Hong Xuyao
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <f1c100s-irq.h>
|
||||
#include <arm32.h>
|
||||
|
||||
#define __irq __attribute__ ((interrupt ("IRQ")))
|
||||
|
||||
#ifndef __IO
|
||||
#define __IO volatile
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
__IO uint32_t INTC_VECTOR_REG; // 0x00
|
||||
__IO uint32_t INTC_BASE_ADDR_REG; // 0x04
|
||||
uint32_t resv1[1]; // 0x08
|
||||
__IO uint32_t NMI_INT_CTRL_REG; // 0x0c
|
||||
__IO uint32_t INTC_PEND_REG[2]; // 0x10
|
||||
uint32_t resv2[2]; // 0x18
|
||||
__IO uint32_t INTC_EN_REG[2]; // 0x20
|
||||
uint32_t resv3[2]; // 0x28
|
||||
__IO uint32_t INTC_MASK_REG[2]; // 0x30
|
||||
uint32_t resv4[2]; // 0x38
|
||||
__IO uint32_t INTC_RESP_REG[2]; // 0x40
|
||||
uint32_t resv5[2]; // 0x48
|
||||
__IO uint32_t INTC_FF_REG[2]; // 0x50
|
||||
uint32_t resv6[2]; // 0x58
|
||||
__IO uint32_t INTC_PRIO_REG[4]; // 0x60
|
||||
} INTC_TypeDef;
|
||||
|
||||
#ifndef COUNTOF
|
||||
#define COUNTOF(ar) (sizeof(ar)/sizeof(ar[0]))
|
||||
#endif
|
||||
|
||||
#define INTC ((INTC_TypeDef*)0x01C20400)
|
||||
|
||||
static IRQHandleTypeDef irq_table[64] __attribute__((used, aligned(32)));
|
||||
|
||||
void arm32_do_irq(struct arm_regs_t * regs)
|
||||
{
|
||||
uint8_t nIRQ = f1c100s_intc_get_nirq();
|
||||
|
||||
// ForceIRQ flag must be cleared by ISR
|
||||
// Otherwise ISR will be entered repeatedly
|
||||
INTC->INTC_FF_REG[nIRQ / 32] &= ~(1 << nIRQ);
|
||||
// Call the drivers ISR
|
||||
f1c100s_intc_dispatch(nIRQ);
|
||||
// Clear pending at the end of ISR
|
||||
f1c100s_intc_clear_pend(nIRQ);
|
||||
}
|
||||
|
||||
void arm32_do_fiq(struct arm_regs_t * regs)
|
||||
{
|
||||
// Call the drivers ISR
|
||||
f1c100s_intc_dispatch(0);
|
||||
// Clear pending at the end of ISR.
|
||||
f1c100s_intc_clear_pend(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read active IRQ number
|
||||
* @return: none
|
||||
*/
|
||||
uint8_t f1c100s_intc_get_nirq(void)
|
||||
{
|
||||
return ((INTC->INTC_VECTOR_REG >> 2) & 0x3F);
|
||||
}
|
||||
|
||||
/*
|
||||
* Execute ISR corresponding to IRQ number
|
||||
* @nIRQ: IRQ number
|
||||
* @return: none
|
||||
*/
|
||||
void f1c100s_intc_dispatch(uint8_t nIRQ)
|
||||
{
|
||||
IRQHandleTypeDef handle = irq_table[nIRQ];
|
||||
if (handle)
|
||||
handle();
|
||||
}
|
||||
|
||||
/*
|
||||
* Set handler function for specified IRQ
|
||||
* @nIRQ: IRQ number
|
||||
* @handle: Handle function
|
||||
* @return: none
|
||||
*/
|
||||
void f1c100s_intc_set_isr(uint8_t nIRQ, IRQHandleTypeDef handle)
|
||||
{
|
||||
if (nIRQ < COUNTOF(irq_table)) {
|
||||
irq_table[nIRQ] = handle;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable IRQ
|
||||
* @nIRQ: IRQ number
|
||||
* @return: none
|
||||
*/
|
||||
void f1c100s_intc_enable_irq(uint8_t nIRQ)
|
||||
{
|
||||
INTC->INTC_EN_REG[nIRQ / 32] |= (1 << (nIRQ % 32));
|
||||
}
|
||||
|
||||
/*
|
||||
* Disable IRQ
|
||||
* @nIRQ: IRQ number
|
||||
* @return: none
|
||||
*/
|
||||
void f1c100s_intc_disable_irq(uint8_t nIRQ)
|
||||
{
|
||||
INTC->INTC_EN_REG[nIRQ / 32] &= ~(1 << (nIRQ % 32));
|
||||
}
|
||||
|
||||
/*
|
||||
* Mask IRQ
|
||||
* @nIRQ: IRQ number
|
||||
* @return: none
|
||||
*/
|
||||
void f1c100s_intc_mask_irq(uint8_t nIRQ)
|
||||
{
|
||||
INTC->INTC_MASK_REG[nIRQ / 32] |= (1 << (nIRQ % 32));
|
||||
}
|
||||
|
||||
/*
|
||||
* Unmask IRQ
|
||||
* @nIRQ: IRQ number
|
||||
* @return: none
|
||||
*/
|
||||
void f1c100s_intc_unmask_irq(uint8_t nIRQ)
|
||||
{
|
||||
INTC->INTC_MASK_REG[nIRQ / 32] &= ~(1 << (nIRQ % 32));
|
||||
}
|
||||
|
||||
/*
|
||||
* Immediately trigger IRQ
|
||||
* @nIRQ: IRQ number
|
||||
* @return: none
|
||||
*/
|
||||
void f1c100s_intc_force_irq(uint8_t nIRQ)
|
||||
{
|
||||
// This bit is to be cleared in IRQ handler
|
||||
INTC->INTC_FF_REG[nIRQ / 32] = (1 << (nIRQ % 32));
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear pending flag
|
||||
* @nIRQ: IRQ number
|
||||
* @return: none
|
||||
*/
|
||||
void f1c100s_intc_clear_pend(uint8_t nIRQ)
|
||||
{
|
||||
INTC->INTC_PEND_REG[nIRQ / 32] = (1 << (nIRQ % 32));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Initialize IRQ module
|
||||
* @return: none
|
||||
*/
|
||||
void f1c100s_intc_init(void)
|
||||
{
|
||||
INTC->INTC_EN_REG[0] = INTC->INTC_EN_REG[1] = 0;
|
||||
INTC->INTC_MASK_REG[0] = INTC->INTC_MASK_REG[1] = 0;
|
||||
INTC->INTC_FF_REG[0] = INTC->INTC_FF_REG[1] = 0;
|
||||
INTC->INTC_RESP_REG[0] = INTC->INTC_RESP_REG[1] = 0;
|
||||
INTC->INTC_PEND_REG[0] = INTC->INTC_PEND_REG[1] = ~0UL;
|
||||
INTC->INTC_BASE_ADDR_REG = 0;
|
||||
INTC->NMI_INT_CTRL_REG = 0;
|
||||
for (unsigned int i = 0; i < COUNTOF(irq_table); i++) {
|
||||
irq_table[i] = 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,313 @@
|
||||
/*
|
||||
* start.S
|
||||
*
|
||||
* Copyright(c) 2007-2018 Jianjun Jiang <8192542@qq.com>
|
||||
* Official site: http://xboot.org
|
||||
* Mobile phone: +86-18665388956
|
||||
* QQ: 8192542
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Exception vector table
|
||||
*/
|
||||
.text
|
||||
.arm
|
||||
|
||||
.global _start
|
||||
_start:
|
||||
/* Boot head information for BROM */
|
||||
.long 0xea000016
|
||||
.byte 'e', 'G', 'O', 'N', '.', 'B', 'T', '0'
|
||||
.long 0, __bootloader_size
|
||||
.byte 'S', 'P', 'L', 2
|
||||
.long 0, 0
|
||||
.long 0, 0, 0, 0, 0, 0, 0, 0
|
||||
.long 0, 0, 0, 0, 0, 0, 0, 0 /* 0x40 - boot params, 0x58 - fel boot type, 0x5c - dram size */
|
||||
|
||||
_vector:
|
||||
b reset
|
||||
ldr pc, _undefined_instruction
|
||||
ldr pc, _software_interrupt
|
||||
ldr pc, _prefetch_abort
|
||||
ldr pc, _data_abort
|
||||
ldr pc, _not_used
|
||||
ldr pc, _irq
|
||||
ldr pc, _fiq
|
||||
|
||||
_undefined_instruction:
|
||||
.word undefined_instruction
|
||||
_software_interrupt:
|
||||
.word software_interrupt
|
||||
_prefetch_abort:
|
||||
.word prefetch_abort
|
||||
_data_abort:
|
||||
.word data_abort
|
||||
_not_used:
|
||||
.word not_used
|
||||
_irq:
|
||||
.word irq
|
||||
_fiq:
|
||||
.word fiq
|
||||
|
||||
/*
|
||||
* The actual reset code
|
||||
*/
|
||||
reset:
|
||||
/* Save boot params to 0x00000040 */
|
||||
ldr r0, =0x00000040
|
||||
str sp, [r0, #0]
|
||||
str lr, [r0, #4]
|
||||
mrs lr, cpsr
|
||||
str lr, [r0, #8]
|
||||
mrc p15, 0, lr, c1, c0, 0
|
||||
str lr, [r0, #12]
|
||||
mrc p15, 0, lr, c1, c0, 0
|
||||
str lr, [r0, #16]
|
||||
|
||||
/* Check boot type just for fel */
|
||||
mov r0, #0x0
|
||||
ldr r1, [r0, #8]
|
||||
ldr r2, =0x4c45462e
|
||||
cmp r1, r2
|
||||
bne 1f
|
||||
ldr r1, =0x1
|
||||
str r1, [r0, #0x58]
|
||||
1: nop
|
||||
|
||||
/* Enter svc mode and mask interrupts */
|
||||
mrs r0, cpsr
|
||||
bic r0, r0, #0x1f
|
||||
orr r0, r0, #0xd3
|
||||
msr cpsr, r0
|
||||
|
||||
/* Set vector to the low address */
|
||||
mrc p15, 0, r0, c1, c0, 0
|
||||
bic r0, #(1<<13)
|
||||
mcr p15, 0, r0, c1, c0, 0
|
||||
|
||||
/* Copy vector to the correct address */
|
||||
adr r0, _vector
|
||||
mrc p15, 0, r2, c1, c0, 0
|
||||
ands r2, r2, #(1 << 13)
|
||||
ldreq r1, =0x00000000
|
||||
ldrne r1, =0xffff0000
|
||||
ldmia r0!, {r2-r8, r10}
|
||||
stmia r1!, {r2-r8, r10}
|
||||
ldmia r0!, {r2-r8, r10}
|
||||
stmia r1!, {r2-r8, r10}
|
||||
|
||||
/* Initial system clock, ddr add uart */
|
||||
bl sys_clock_init
|
||||
bl sys_dram_init
|
||||
bl sys_uart_init
|
||||
|
||||
/* Boot speed up, leave slower sram */
|
||||
adr r0, _start
|
||||
ldr r1, =_start
|
||||
cmp r0, r1
|
||||
beq _speedup
|
||||
ldr r0, =0x81f80000
|
||||
adr r1, _start
|
||||
mov r2, #0x4000
|
||||
bl memcpy
|
||||
ldr r0, =_speedup
|
||||
ldr r1, =_start
|
||||
sub r0, r0, r1
|
||||
ldr r1, =0x81f80000
|
||||
add r0, r0, r1
|
||||
mov pc, r0
|
||||
_speedup:
|
||||
nop
|
||||
|
||||
/* Copyself to link address */
|
||||
adr r0, _start
|
||||
ldr r1, =_start
|
||||
cmp r0, r1
|
||||
beq 1f
|
||||
bl sys_copyself
|
||||
1: nop
|
||||
|
||||
/* Initialize stacks */
|
||||
mrs r0, cpsr
|
||||
bic r0, r0, #0x1f
|
||||
orr r1, r0, #0x1b
|
||||
msr cpsr_cxsf, r1
|
||||
ldr sp, _stack_und_end
|
||||
|
||||
bic r0, r0, #0x1f
|
||||
orr r1, r0, #0x17
|
||||
msr cpsr_cxsf, r1
|
||||
ldr sp, _stack_abt_end
|
||||
|
||||
bic r0, r0, #0x1f
|
||||
orr r1, r0, #0x12
|
||||
msr cpsr_cxsf, r1
|
||||
ldr sp, _stack_irq_end
|
||||
|
||||
bic r0, r0, #0x1f
|
||||
orr r1, r0, #0x11
|
||||
msr cpsr_cxsf, r1
|
||||
ldr sp, _stack_fiq_end
|
||||
|
||||
bic r0, r0, #0x1f
|
||||
orr r1, r0, #0x13
|
||||
msr cpsr_cxsf, r1
|
||||
ldr sp, _stack_srv_end
|
||||
|
||||
/* Copy data section */
|
||||
ldr r0, _data_start
|
||||
ldr r1, _data_shadow_start
|
||||
ldr r2, _data_shadow_end
|
||||
sub r2, r2, r1
|
||||
bl memcpy
|
||||
|
||||
/* Clear bss section */
|
||||
ldr r0, _bss_start
|
||||
ldr r2, _bss_end
|
||||
sub r2, r2, r0
|
||||
mov r1, #0
|
||||
bl memset
|
||||
|
||||
/* Call _main */
|
||||
ldr r1, =_main
|
||||
mov pc, r1
|
||||
_main:
|
||||
bl main
|
||||
b _main
|
||||
|
||||
.global return_to_fel
|
||||
return_to_fel:
|
||||
mov r0, #0x4
|
||||
mov r1, #'e'
|
||||
strb r1, [r0, #0]
|
||||
mov r1, #'G'
|
||||
strb r1, [r0, #1]
|
||||
mov r1, #'O'
|
||||
strb r1, [r0, #2]
|
||||
mov r1, #'N'
|
||||
strb r1, [r0, #3]
|
||||
mov r1, #'.'
|
||||
strb r1, [r0, #4]
|
||||
mov r1, #'F'
|
||||
strb r1, [r0, #5]
|
||||
mov r1, #'E'
|
||||
strb r1, [r0, #6]
|
||||
mov r1, #'L'
|
||||
strb r1, [r0, #7]
|
||||
ldr r0, =0x00000040
|
||||
ldr sp, [r0, #0]
|
||||
ldr lr, [r0, #4]
|
||||
ldr r1, [r0, #16]
|
||||
mcr p15, 0, r1, c1, c0, 0
|
||||
ldr r1, [r0, #12]
|
||||
mcr p15, 0, r1, c1, c0, 0
|
||||
ldr r1, [r0, #8]
|
||||
msr cpsr, r1
|
||||
bx lr
|
||||
|
||||
/*
|
||||
* Exception handlers
|
||||
*/
|
||||
.align 5
|
||||
undefined_instruction:
|
||||
b .
|
||||
|
||||
.align 5
|
||||
software_interrupt:
|
||||
b .
|
||||
|
||||
.align 5
|
||||
prefetch_abort:
|
||||
b .
|
||||
|
||||
.align 5
|
||||
data_abort:
|
||||
b .
|
||||
|
||||
.align 5
|
||||
not_used:
|
||||
b .
|
||||
|
||||
.align 5
|
||||
irq:
|
||||
ldr sp, _stack_irq_end
|
||||
sub sp, sp, #72
|
||||
stmia sp, {r0 - r12}
|
||||
add r8, sp, #60
|
||||
stmdb r8, {sp, lr}^
|
||||
str lr, [r8, #0]
|
||||
mrs r6, spsr
|
||||
str r6, [r8, #4]
|
||||
str r0, [r8, #8]
|
||||
mov r0, sp
|
||||
bl arm32_do_irq
|
||||
ldmia sp, {r0 - lr}^
|
||||
mov r0, r0
|
||||
ldr lr, [sp, #60]
|
||||
add sp, sp, #72
|
||||
subs pc, lr, #4
|
||||
|
||||
.align 5
|
||||
fiq:
|
||||
ldr sp, _stack_irq_end
|
||||
sub sp, sp, #72
|
||||
stmia sp, {r0 - r12}
|
||||
add r8, sp, #60
|
||||
stmdb r8, {sp, lr}^
|
||||
str lr, [r8, #0]
|
||||
mrs r6, spsr
|
||||
str r6, [r8, #4]
|
||||
str r0, [r8, #8]
|
||||
mov r0, sp
|
||||
bl arm32_do_fiq
|
||||
ldmia sp, {r0 - lr}^
|
||||
mov r0, r0
|
||||
ldr lr, [sp, #60]
|
||||
add sp, sp, #72
|
||||
subs pc, lr, #4
|
||||
|
||||
/*
|
||||
* The location of section
|
||||
*/
|
||||
.align 4
|
||||
_image_start:
|
||||
.long __image_start
|
||||
_image_end:
|
||||
.long __image_end
|
||||
_data_shadow_start:
|
||||
.long __data_shadow_start
|
||||
_data_shadow_end:
|
||||
.long __data_shadow_end
|
||||
_data_start:
|
||||
.long __data_start
|
||||
_data_end:
|
||||
.long __data_end
|
||||
_bss_start:
|
||||
.long __bss_start
|
||||
_bss_end:
|
||||
.long __bss_end
|
||||
_stack_und_end:
|
||||
.long __stack_und_end
|
||||
_stack_abt_end:
|
||||
.long __stack_abt_end
|
||||
_stack_irq_end:
|
||||
.long __stack_irq_end
|
||||
_stack_fiq_end:
|
||||
.long __stack_fiq_end
|
||||
_stack_srv_end:
|
||||
.long __stack_srv_end
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* sys-clock.c
|
||||
*
|
||||
* Copyright(c) 2007-2018 Jianjun Jiang <8192542@qq.com>
|
||||
* Official site: http://xboot.org
|
||||
* Mobile phone: +86-18665388956
|
||||
* QQ: 8192542
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
//#include <xboot.h>
|
||||
#include <stdint.h>
|
||||
#include <f1c100s/reg-ccu.h>
|
||||
#include <io.h>
|
||||
|
||||
static inline void sdelay(int loops)
|
||||
{
|
||||
__asm__ __volatile__ ("1:\n" "subs %0, %1, #1\n"
|
||||
"bne 1b":"=r" (loops):"0"(loops));
|
||||
}
|
||||
|
||||
static void wait_pll_stable(uint32_t base)
|
||||
{
|
||||
uint32_t rval = 0;
|
||||
uint32_t time = 0xfff;
|
||||
|
||||
do {
|
||||
rval = read32(base);
|
||||
time--;
|
||||
} while(time && !(rval & (1 << 28)));
|
||||
}
|
||||
|
||||
static void clock_set_pll_cpu(uint32_t clk)
|
||||
{
|
||||
uint32_t n, k, m, p;
|
||||
uint32_t rval = 0;
|
||||
uint32_t div = 0;
|
||||
|
||||
if(clk > 720000000)
|
||||
clk = 720000000;
|
||||
|
||||
if((clk % 24000000) == 0)
|
||||
{
|
||||
div = clk / 24000000;
|
||||
n = div - 1;
|
||||
k = 0;
|
||||
m = 0;
|
||||
p = 0;
|
||||
}
|
||||
else if((clk % 12000000) == 0)
|
||||
{
|
||||
m = 1;
|
||||
div = clk / 12000000;
|
||||
if((div % 3) == 0)
|
||||
k = 2;
|
||||
else if((div % 4) == 0)
|
||||
k = 3;
|
||||
else
|
||||
k = 1;
|
||||
n = (div / (k + 1)) - 1;
|
||||
p = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
div = clk / 24000000;
|
||||
n = div - 1;
|
||||
k = 0;
|
||||
m = 0;
|
||||
p = 0;
|
||||
}
|
||||
|
||||
rval = read32(F1C100S_CCU_BASE + CCU_PLL_CPU_CTRL);
|
||||
rval &= ~((0x3 << 16) | (0x1f << 8) | (0x3 << 4) | (0x3 << 0));
|
||||
rval |= (1U << 31) | (p << 16) | (n << 8) | (k << 4) | m;
|
||||
write32(F1C100S_CCU_BASE + CCU_PLL_CPU_CTRL, rval);
|
||||
wait_pll_stable(F1C100S_CCU_BASE + CCU_PLL_CPU_CTRL);
|
||||
}
|
||||
|
||||
void sys_clock_init(void)
|
||||
{
|
||||
uint32_t val;
|
||||
|
||||
write32(F1C100S_CCU_BASE + CCU_PLL_STABLE_TIME0, 0x1ff);
|
||||
write32(F1C100S_CCU_BASE + CCU_PLL_STABLE_TIME1, 0x1ff);
|
||||
|
||||
val = read32(F1C100S_CCU_BASE + CCU_CPU_CFG);
|
||||
val &= ~(0x3 << 16);
|
||||
val |= (0x1 << 16);
|
||||
write32(F1C100S_CCU_BASE + CCU_CPU_CFG, val);
|
||||
sdelay(100);
|
||||
|
||||
write32(F1C100S_CCU_BASE + CCU_PLL_VIDEO_CTRL, 0x81004107);
|
||||
sdelay(100);
|
||||
write32(F1C100S_CCU_BASE + CCU_PLL_PERIPH_CTRL, 0x80041800);
|
||||
sdelay(100);
|
||||
write32(F1C100S_CCU_BASE + CCU_AHB_APB_CFG, 0x00003180);
|
||||
sdelay(100);
|
||||
|
||||
val = read32(F1C100S_CCU_BASE + CCU_DRAM_CLK_GATE);
|
||||
val |= (0x1 << 26) | (0x1 << 24);
|
||||
write32(F1C100S_CCU_BASE + CCU_DRAM_CLK_GATE, val);
|
||||
sdelay(100);
|
||||
|
||||
clock_set_pll_cpu(408000000);
|
||||
val = read32(F1C100S_CCU_BASE + CCU_CPU_CFG);
|
||||
val &= ~(0x3 << 16);
|
||||
val |= (0x2 << 16);
|
||||
write32(F1C100S_CCU_BASE + CCU_CPU_CFG, val);
|
||||
sdelay(100);
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* sys-copyself.c
|
||||
*
|
||||
* Copyright(c) 2007-2018 Jianjun Jiang <8192542@qq.com>
|
||||
* Official site: http://xboot.org
|
||||
* Mobile phone: +86-18665388956
|
||||
* QQ: 8192542
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
#include <stdint.h>
|
||||
|
||||
extern unsigned char __image_start;
|
||||
extern unsigned char __image_end;
|
||||
extern void return_to_fel(void);
|
||||
extern void sys_mmu_init(void);
|
||||
extern void sys_uart_putc(char c);
|
||||
extern void sys_spi_flash_init(void);
|
||||
extern void sys_spi_flash_exit(void);
|
||||
extern void sys_spi_flash_read(int addr, void * buf, int count);
|
||||
|
||||
enum {
|
||||
BOOT_DEVICE_FEL = 0,
|
||||
BOOT_DEVICE_SPI = 1,
|
||||
BOOT_DEVICE_MMC = 2,
|
||||
};
|
||||
|
||||
static int get_boot_device(void)
|
||||
{
|
||||
uint32_t * t = (void *)0x00000058;
|
||||
|
||||
if(t[0] == 0x1)
|
||||
return BOOT_DEVICE_FEL;
|
||||
return BOOT_DEVICE_SPI;
|
||||
}
|
||||
|
||||
void sys_copyself(void)
|
||||
{
|
||||
int d = get_boot_device();
|
||||
void * mem;
|
||||
uint32_t size;
|
||||
|
||||
if(d == BOOT_DEVICE_FEL)
|
||||
{
|
||||
sys_uart_putc('B');
|
||||
sys_uart_putc('o');
|
||||
sys_uart_putc('o');
|
||||
sys_uart_putc('t');
|
||||
sys_uart_putc(' ');
|
||||
sys_uart_putc('t');
|
||||
sys_uart_putc('o');
|
||||
sys_uart_putc(' ');
|
||||
sys_uart_putc('F');
|
||||
sys_uart_putc('E');
|
||||
sys_uart_putc('L');
|
||||
sys_uart_putc(' ');
|
||||
sys_uart_putc('m');
|
||||
sys_uart_putc('o');
|
||||
sys_uart_putc('d');
|
||||
sys_uart_putc('e');
|
||||
sys_uart_putc('\r');
|
||||
sys_uart_putc('\n');
|
||||
return_to_fel();
|
||||
}
|
||||
else if(d == BOOT_DEVICE_SPI)
|
||||
{
|
||||
sys_uart_putc('B');
|
||||
sys_uart_putc('o');
|
||||
sys_uart_putc('o');
|
||||
sys_uart_putc('t');
|
||||
sys_uart_putc(' ');
|
||||
sys_uart_putc('t');
|
||||
sys_uart_putc('o');
|
||||
sys_uart_putc(' ');
|
||||
sys_uart_putc('S');
|
||||
sys_uart_putc('P');
|
||||
sys_uart_putc('I');
|
||||
sys_uart_putc(' ');
|
||||
sys_uart_putc('m');
|
||||
sys_uart_putc('o');
|
||||
sys_uart_putc('d');
|
||||
sys_uart_putc('e');
|
||||
sys_uart_putc('\r');
|
||||
sys_uart_putc('\n');
|
||||
mem = (void *)&__image_start;
|
||||
size = &__image_end - &__image_start;
|
||||
sys_mmu_init();
|
||||
|
||||
sys_spi_flash_init();
|
||||
sys_spi_flash_read(0, mem, size);
|
||||
sys_spi_flash_exit();
|
||||
}
|
||||
else if(d == BOOT_DEVICE_MMC)
|
||||
{
|
||||
mem = (void *)&__image_start;
|
||||
size = (&__image_end - &__image_start + 512) >> 9;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,506 @@
|
||||
/*
|
||||
* sys-dram.c
|
||||
*
|
||||
* Copyright(c) 2007-2018 Jianjun Jiang <8192542@qq.com>
|
||||
* Official site: http://xboot.org
|
||||
* Mobile phone: +86-18665388956
|
||||
* QQ: 8192542
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <f1c100s/reg-ccu.h>
|
||||
#include <f1c100s/reg-dram.h>
|
||||
#include <io.h>
|
||||
|
||||
#define PLL_DDR_CLK (156000000)
|
||||
#define SDR_T_CAS (0x2)
|
||||
#define SDR_T_RAS (0x8)
|
||||
#define SDR_T_RCD (0x3)
|
||||
#define SDR_T_RP (0x3)
|
||||
#define SDR_T_WR (0x3)
|
||||
#define SDR_T_RFC (0xd)
|
||||
#define SDR_T_XSR (0xf9)
|
||||
#define SDR_T_RC (0xb)
|
||||
#define SDR_T_INIT (0x8)
|
||||
#define SDR_T_INIT_REF (0x7)
|
||||
#define SDR_T_WTR (0x2)
|
||||
#define SDR_T_RRD (0x2)
|
||||
#define SDR_T_XP (0x0)
|
||||
|
||||
enum dram_type_t
|
||||
{
|
||||
DRAM_TYPE_SDR = 0,
|
||||
DRAM_TYPE_DDR = 1,
|
||||
DRAM_TYPE_MDDR = 2,
|
||||
};
|
||||
|
||||
struct dram_para_t
|
||||
{
|
||||
uint32_t base; /* dram base address */
|
||||
uint32_t size; /* dram size (unit: MByte) */
|
||||
uint32_t clk; /* dram work clock (unit: MHz) */
|
||||
uint32_t access_mode; /* 0: interleave mode 1: sequence mode */
|
||||
uint32_t cs_num; /* dram chip count 1: one chip 2: two chip */
|
||||
uint32_t ddr8_remap; /* for 8bits data width DDR 0: normal 1: 8bits */
|
||||
enum dram_type_t sdr_ddr;
|
||||
uint32_t bwidth; /* dram bus width */
|
||||
uint32_t col_width; /* column address width */
|
||||
uint32_t row_width; /* row address width */
|
||||
uint32_t bank_size; /* dram bank count */
|
||||
uint32_t cas; /* dram cas */
|
||||
};
|
||||
|
||||
static inline void sdelay(int loops)
|
||||
{
|
||||
__asm__ __volatile__ ("1:\n" "subs %0, %1, #1\n"
|
||||
"bne 1b":"=r" (loops):"0"(loops));
|
||||
}
|
||||
|
||||
static void dram_delay(int ms)
|
||||
{
|
||||
sdelay(ms * 2 * 1000);
|
||||
}
|
||||
|
||||
static int dram_initial(void)
|
||||
{
|
||||
unsigned int time = 0xffffff;
|
||||
|
||||
write32(F1C100S_DRAM_BASE + DRAM_SCTLR, read32(F1C100S_DRAM_BASE + DRAM_SCTLR) | 0x1);
|
||||
while((read32(F1C100S_DRAM_BASE + DRAM_SCTLR) & 0x1) && time--)
|
||||
{
|
||||
if(time == 0)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dram_delay_scan(void)
|
||||
{
|
||||
unsigned int time = 0xffffff;
|
||||
|
||||
write32(F1C100S_DRAM_BASE + DRAM_DDLYR, read32(F1C100S_DRAM_BASE + DRAM_DDLYR) | 0x1);
|
||||
while((read32(F1C100S_DRAM_BASE + DRAM_DDLYR) & 0x1) && time--)
|
||||
{
|
||||
if(time == 0)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void dram_set_autofresh_cycle(uint32_t clk)
|
||||
{
|
||||
uint32_t val = 0;
|
||||
uint32_t row = 0;
|
||||
uint32_t temp = 0;
|
||||
|
||||
row = read32(F1C100S_DRAM_BASE + DRAM_SCONR);
|
||||
row &= 0x1e0;
|
||||
row >>= 0x5;
|
||||
|
||||
if(row == 0xc)
|
||||
{
|
||||
if(clk >= 1000000)
|
||||
{
|
||||
temp = clk + (clk >> 3) + (clk >> 4) + (clk >> 5);
|
||||
while(temp >= (10000000 >> 6))
|
||||
{
|
||||
temp -= (10000000 >> 6);
|
||||
val++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
val = (clk * 499) >> 6;
|
||||
}
|
||||
}
|
||||
else if(row == 0xb)
|
||||
{
|
||||
if(clk >= 1000000)
|
||||
{
|
||||
temp = clk + (clk >> 3) + (clk >> 4) + (clk >> 5);
|
||||
while(temp >= (10000000 >> 7))
|
||||
{
|
||||
temp -= (10000000 >> 7);
|
||||
val++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
val = (clk * 499) >> 5;
|
||||
}
|
||||
}
|
||||
write32(F1C100S_DRAM_BASE + DRAM_SREFR, val);
|
||||
}
|
||||
|
||||
static int dram_para_setup(struct dram_para_t * para)
|
||||
{
|
||||
uint32_t val = 0;
|
||||
|
||||
val = (para->ddr8_remap) |
|
||||
(0x1 << 1) |
|
||||
((para->bank_size >> 2) << 3) |
|
||||
((para->cs_num >> 1) << 4) |
|
||||
((para->row_width - 1) << 5) |
|
||||
((para->col_width - 1) << 9) |
|
||||
((para->sdr_ddr ? (para->bwidth >> 4) : (para->bwidth >> 5)) << 13) |
|
||||
(para->access_mode << 15) |
|
||||
(para->sdr_ddr << 16);
|
||||
|
||||
write32(F1C100S_DRAM_BASE + DRAM_SCONR, val);
|
||||
write32(F1C100S_DRAM_BASE + DRAM_SCTLR, read32(F1C100S_DRAM_BASE + DRAM_SCTLR) | (0x1 << 19));
|
||||
return dram_initial();
|
||||
}
|
||||
|
||||
static uint32_t dram_check_delay(uint32_t bwidth)
|
||||
{
|
||||
uint32_t dsize;
|
||||
uint32_t i,j;
|
||||
uint32_t num = 0;
|
||||
uint32_t dflag = 0;
|
||||
|
||||
dsize = ((bwidth == 16) ? 4 : 2);
|
||||
for(i = 0; i < dsize; i++)
|
||||
{
|
||||
if(i == 0)
|
||||
dflag = read32(F1C100S_DRAM_BASE + DRAM_DRPTR0);
|
||||
else if(i == 1)
|
||||
dflag = read32(F1C100S_DRAM_BASE + DRAM_DRPTR1);
|
||||
else if(i == 2)
|
||||
dflag = read32(F1C100S_DRAM_BASE + DRAM_DRPTR2);
|
||||
else if(i == 3)
|
||||
dflag = read32(F1C100S_DRAM_BASE + DRAM_DRPTR3);
|
||||
|
||||
for(j = 0; j < 32; j++)
|
||||
{
|
||||
if(dflag & 0x1)
|
||||
num++;
|
||||
dflag >>= 1;
|
||||
}
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
static int sdr_readpipe_scan(void)
|
||||
{
|
||||
uint32_t k = 0;
|
||||
|
||||
for(k = 0; k < 32; k++)
|
||||
{
|
||||
write32(0x80000000 + 4 * k, k);
|
||||
}
|
||||
for(k = 0; k < 32; k++)
|
||||
{
|
||||
if(read32(0x80000000 + 4 * k) != k)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static uint32_t sdr_readpipe_select(void)
|
||||
{
|
||||
uint32_t value = 0;
|
||||
uint32_t i = 0;
|
||||
for(i = 0; i < 8; i++)
|
||||
{
|
||||
write32(F1C100S_DRAM_BASE + DRAM_SCTLR, (read32(F1C100S_DRAM_BASE + DRAM_SCTLR) & (~(0x7 << 6))) | (i << 6));
|
||||
if(sdr_readpipe_scan())
|
||||
{
|
||||
value = i;
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
static uint32_t dram_check_type(struct dram_para_t * para)
|
||||
{
|
||||
uint32_t val = 0;
|
||||
uint32_t times = 0;
|
||||
uint32_t i;
|
||||
|
||||
for(i = 0; i < 8; i++)
|
||||
{
|
||||
val = read32(F1C100S_DRAM_BASE + DRAM_SCTLR);
|
||||
val &= ~(0x7 << 6);
|
||||
val |= (i << 6);
|
||||
write32(F1C100S_DRAM_BASE + DRAM_SCTLR, val);
|
||||
|
||||
dram_delay_scan();
|
||||
if(read32(F1C100S_DRAM_BASE + DRAM_DDLYR) & 0x30)
|
||||
times++;
|
||||
}
|
||||
|
||||
if(times == 8)
|
||||
{
|
||||
para->sdr_ddr = DRAM_TYPE_SDR;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
para->sdr_ddr = DRAM_TYPE_DDR;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t dram_scan_readpipe(struct dram_para_t * para)
|
||||
{
|
||||
uint32_t i, rp_best = 0, rp_val = 0;
|
||||
uint32_t val = 0;
|
||||
uint32_t readpipe[8];
|
||||
|
||||
if(para->sdr_ddr == DRAM_TYPE_DDR)
|
||||
{
|
||||
for(i = 0; i < 8; i++)
|
||||
{
|
||||
val = read32(F1C100S_DRAM_BASE + DRAM_SCTLR);
|
||||
val &= ~(0x7 << 6);
|
||||
val |= (i << 6);
|
||||
write32(F1C100S_DRAM_BASE + DRAM_SCTLR, val);
|
||||
dram_delay_scan();
|
||||
readpipe[i] = 0;
|
||||
if((((read32(F1C100S_DRAM_BASE + DRAM_DDLYR) >> 4) & 0x3) == 0x0) &&
|
||||
(((read32(F1C100S_DRAM_BASE + DRAM_DDLYR) >> 4) & 0x1) == 0x0))
|
||||
{
|
||||
readpipe[i] = dram_check_delay(para->bwidth);
|
||||
}
|
||||
if(rp_val < readpipe[i])
|
||||
{
|
||||
rp_val = readpipe[i];
|
||||
rp_best = i;
|
||||
}
|
||||
}
|
||||
val = read32(F1C100S_DRAM_BASE + DRAM_SCTLR);
|
||||
val &= ~(0x7 << 6);
|
||||
val |= (rp_best << 6);
|
||||
write32(F1C100S_DRAM_BASE + DRAM_SCTLR, val);
|
||||
dram_delay_scan();
|
||||
}
|
||||
else
|
||||
{
|
||||
val = read32(F1C100S_DRAM_BASE + DRAM_SCONR);
|
||||
val &= (~(0x1 << 16));
|
||||
val &= (~(0x3 << 13));
|
||||
write32(F1C100S_DRAM_BASE + DRAM_SCONR, val);
|
||||
rp_best = sdr_readpipe_select();
|
||||
val = read32(F1C100S_DRAM_BASE + DRAM_SCTLR);
|
||||
val &= ~(0x7 << 6);
|
||||
val |= (rp_best << 6);
|
||||
write32(F1C100S_DRAM_BASE + DRAM_SCTLR, val);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t dram_get_dram_size(struct dram_para_t * para)
|
||||
{
|
||||
uint32_t colflag = 10, rowflag = 13;
|
||||
uint32_t i = 0;
|
||||
uint32_t val1 = 0;
|
||||
uint32_t count = 0;
|
||||
uint32_t addr1, addr2;
|
||||
|
||||
para->col_width = colflag;
|
||||
para->row_width = rowflag;
|
||||
dram_para_setup(para);
|
||||
dram_scan_readpipe(para);
|
||||
for(i = 0; i < 32; i++)
|
||||
{
|
||||
*((uint32_t *)(0x80000200 + i)) = 0x11111111;
|
||||
*((uint32_t *)(0x80000600 + i)) = 0x22222222;
|
||||
}
|
||||
for(i = 0; i < 32; i++)
|
||||
{
|
||||
val1 = *((uint32_t *)(0x80000200 + i));
|
||||
if(val1 == 0x22222222)
|
||||
count++;
|
||||
}
|
||||
if(count == 32)
|
||||
{
|
||||
colflag = 9;
|
||||
}
|
||||
else
|
||||
{
|
||||
colflag = 10;
|
||||
}
|
||||
count = 0;
|
||||
para->col_width = colflag;
|
||||
para->row_width = rowflag;
|
||||
dram_para_setup(para);
|
||||
if(colflag == 10)
|
||||
{
|
||||
addr1 = 0x80400000;
|
||||
addr2 = 0x80c00000;
|
||||
}
|
||||
else
|
||||
{
|
||||
addr1 = 0x80200000;
|
||||
addr2 = 0x80600000;
|
||||
}
|
||||
for(i = 0; i < 32; i++)
|
||||
{
|
||||
*((uint32_t *)(addr1 + i)) = 0x33333333;
|
||||
*((uint32_t *)(addr2 + i)) = 0x44444444;
|
||||
}
|
||||
for(i = 0; i < 32; i++)
|
||||
{
|
||||
val1 = *((uint32_t *)(addr1 + i));
|
||||
if(val1 == 0x44444444)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if(count == 32)
|
||||
{
|
||||
rowflag = 12;
|
||||
}
|
||||
else
|
||||
{
|
||||
rowflag = 13;
|
||||
}
|
||||
para->col_width = colflag;
|
||||
para->row_width = rowflag;
|
||||
if(para->row_width != 13)
|
||||
{
|
||||
para->size = 16;
|
||||
}
|
||||
else if(para->col_width == 10)
|
||||
{
|
||||
para->size = 64;
|
||||
}
|
||||
else
|
||||
{
|
||||
para->size = 32;
|
||||
}
|
||||
dram_set_autofresh_cycle(para->clk);
|
||||
para->access_mode = 0;
|
||||
dram_para_setup(para);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dram_init(struct dram_para_t * para)
|
||||
{
|
||||
uint32_t val = 0;
|
||||
uint32_t i;
|
||||
|
||||
write32(0x01c20800 + 0x24, read32(0x01c20800 + 0x24) | (0x7 << 12));
|
||||
dram_delay(5);
|
||||
if(((para->cas) >> 3) & 0x1)
|
||||
{
|
||||
write32(0x01c20800 + 0x2c4, read32(0x01c20800 + 0x2c4) | (0x1 << 23) | (0x20 << 17));
|
||||
}
|
||||
if((para->clk >= 144) && (para->clk <= 180))
|
||||
{
|
||||
write32(0x01c20800 + 0x2c0, 0xaaa);
|
||||
}
|
||||
if(para->clk >= 180)
|
||||
{
|
||||
write32(0x01c20800 + 0x2c0, 0xfff);
|
||||
}
|
||||
if((para->clk) <= 96)
|
||||
{
|
||||
val = (0x1 << 0) | (0x0 << 4) | (((para->clk * 2) / 12 - 1) << 8) | (0x1u << 31);
|
||||
}
|
||||
else
|
||||
{
|
||||
val = (0x0 << 0) | (0x0 << 4) | (((para->clk * 2) / 24 - 1) << 8) | (0x1u << 31);
|
||||
}
|
||||
|
||||
if(para->cas & (0x1 << 4))
|
||||
{
|
||||
write32(F1C100S_CCU_BASE + CCU_PLL_DDR0_PAT, 0xd1303333);
|
||||
}
|
||||
else if(para->cas & (0x1 << 5))
|
||||
{
|
||||
write32(F1C100S_CCU_BASE + CCU_PLL_DDR0_PAT, 0xcce06666);
|
||||
}
|
||||
else if(para->cas & (0x1 << 6))
|
||||
{
|
||||
write32(F1C100S_CCU_BASE + CCU_PLL_DDR0_PAT, 0xc8909999);
|
||||
}
|
||||
else if(para->cas & (0x1 << 7))
|
||||
{
|
||||
write32(F1C100S_CCU_BASE + CCU_PLL_DDR0_PAT, 0xc440cccc);
|
||||
}
|
||||
if(para->cas & (0xf << 4))
|
||||
{
|
||||
val |= 0x1 << 24;
|
||||
}
|
||||
write32(F1C100S_CCU_BASE + CCU_PLL_DDR_CTRL, val);
|
||||
write32(F1C100S_CCU_BASE + CCU_PLL_DDR_CTRL, read32(F1C100S_CCU_BASE + CCU_PLL_DDR_CTRL) | (0x1 << 20));
|
||||
while((read32(F1C100S_CCU_BASE + CCU_PLL_DDR_CTRL) & (1 << 28)) == 0);
|
||||
dram_delay(5);
|
||||
write32(F1C100S_CCU_BASE + CCU_BUS_CLK_GATE0, read32(F1C100S_CCU_BASE + CCU_BUS_CLK_GATE0) | (0x1 << 14));
|
||||
write32(F1C100S_CCU_BASE + CCU_BUS_SOFT_RST0, read32(F1C100S_CCU_BASE + CCU_BUS_SOFT_RST0) & ~(0x1 << 14));
|
||||
for(i = 0; i < 10; i++)
|
||||
continue;
|
||||
write32(F1C100S_CCU_BASE + CCU_BUS_SOFT_RST0, read32(F1C100S_CCU_BASE + CCU_BUS_SOFT_RST0) | (0x1 << 14));
|
||||
|
||||
val = read32(0x01c20800 + 0x2c4);
|
||||
(para->sdr_ddr == DRAM_TYPE_DDR) ? (val |= (0x1 << 16)) : (val &= ~(0x1 << 16));
|
||||
write32(0x01c20800 + 0x2c4, val);
|
||||
|
||||
val = (SDR_T_CAS << 0) | (SDR_T_RAS << 3) | (SDR_T_RCD << 7) | (SDR_T_RP << 10) | (SDR_T_WR << 13) | (SDR_T_RFC << 15) | (SDR_T_XSR << 19) | (SDR_T_RC << 28);
|
||||
write32(F1C100S_DRAM_BASE + DRAM_STMG0R, val);
|
||||
val = (SDR_T_INIT << 0) | (SDR_T_INIT_REF << 16) | (SDR_T_WTR << 20) | (SDR_T_RRD << 22) | (SDR_T_XP << 25);
|
||||
write32(F1C100S_DRAM_BASE + DRAM_STMG1R, val);
|
||||
dram_para_setup(para);
|
||||
dram_check_type(para);
|
||||
|
||||
val = read32(0x01c20800 + 0x2c4);
|
||||
(para->sdr_ddr == DRAM_TYPE_DDR) ? (val |= (0x1 << 16)) : (val &= ~(0x1 << 16));
|
||||
write32(0x01c20800 + 0x2c4, val);
|
||||
|
||||
dram_set_autofresh_cycle(para->clk);
|
||||
dram_scan_readpipe(para);
|
||||
dram_get_dram_size(para);
|
||||
|
||||
for(i = 0; i < 128; i++)
|
||||
{
|
||||
*((volatile uint32_t *)(para->base + 4 * i)) = para->base + 4 * i;
|
||||
}
|
||||
|
||||
for(i = 0; i < 128; i++)
|
||||
{
|
||||
if(*((volatile uint32_t *)(para->base + 4 * i)) != (para->base + 4 * i))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void sys_dram_init(void)
|
||||
{
|
||||
struct dram_para_t para;
|
||||
uint32_t * dsz = (void *)0x0000005c;
|
||||
|
||||
para.base = 0x80000000;
|
||||
para.size = 32;
|
||||
para.clk = PLL_DDR_CLK / 1000000;
|
||||
para.access_mode = 1;
|
||||
para.cs_num = 1;
|
||||
para.ddr8_remap = 0;
|
||||
para.sdr_ddr = DRAM_TYPE_DDR;
|
||||
para.bwidth = 16;
|
||||
para.col_width = 10;
|
||||
para.row_width = 13;
|
||||
para.bank_size = 4;
|
||||
para.cas = 0x3;
|
||||
|
||||
if((dsz[0] >> 24) == 'X')
|
||||
return;
|
||||
if(dram_init(¶))
|
||||
dsz[0] = (((uint32_t)'X') << 24) | (para.size << 0);
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* sys-mmu.c
|
||||
*
|
||||
* Copyright(c) 2007-2018 Jianjun Jiang <8192542@qq.com>
|
||||
* Official site: http://xboot.org
|
||||
* Mobile phone: +86-18665388956
|
||||
* QQ: 8192542
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <io.h>
|
||||
#include <sizes.h>
|
||||
#include <arm32.h>
|
||||
|
||||
static void map_l1_section(uint32_t * ttb, virtual_addr_t virt, physical_addr_t phys, physical_size_t size, int type)
|
||||
{
|
||||
physical_size_t i;
|
||||
|
||||
virt >>= 20;
|
||||
phys >>= 20;
|
||||
size >>= 20;
|
||||
type &= 0x3;
|
||||
|
||||
for(i = size; i > 0; i--, virt++, phys++)
|
||||
ttb[virt] = (phys << 20) | (0x3 << 10) | (0x0 << 5) | (type << 2) | (0x2 << 0);
|
||||
}
|
||||
|
||||
void sys_mmu_init(void)
|
||||
{
|
||||
uint32_t * ttb = (uint32_t *)(0x80000000 + SZ_1M * 31);
|
||||
|
||||
map_l1_section(ttb, 0x00000000, 0x00000000, SZ_2G, 0);
|
||||
map_l1_section(ttb, 0x80000000, 0x80000000, SZ_2G, 0);
|
||||
map_l1_section(ttb, 0x80000000, 0x80000000, SZ_1M * 32, 3);
|
||||
|
||||
arm32_ttb_set((uint32_t)(ttb));
|
||||
arm32_tlb_invalidate();
|
||||
arm32_domain_set(0x3);
|
||||
arm32_mmu_enable();
|
||||
arm32_icache_enable();
|
||||
arm32_dcache_enable();
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
* sys-spi-flash.c
|
||||
*
|
||||
* Copyright(c) 2007-2018 Jianjun Jiang <8192542@qq.com>
|
||||
* Official site: http://xboot.org
|
||||
* Mobile phone: +86-18665388956
|
||||
* QQ: 8192542
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <types.h>
|
||||
#include <string.h>
|
||||
#include <io.h>
|
||||
|
||||
enum {
|
||||
SPI_GCR = 0x04,
|
||||
SPI_TCR = 0x08,
|
||||
SPI_IER = 0x10,
|
||||
SPI_ISR = 0x14,
|
||||
SPI_FCR = 0x18,
|
||||
SPI_FSR = 0x1c,
|
||||
SPI_WCR = 0x20,
|
||||
SPI_CCR = 0x24,
|
||||
SPI_MBC = 0x30,
|
||||
SPI_MTC = 0x34,
|
||||
SPI_BCC = 0x38,
|
||||
SPI_TXD = 0x200,
|
||||
SPI_RXD = 0x300,
|
||||
};
|
||||
|
||||
void sys_spi_flash_init(void)
|
||||
{
|
||||
virtual_addr_t addr;
|
||||
uint32_t val;
|
||||
|
||||
/* Config GPIOC0, GPIOC1, GPIOC2 and GPIOC3 */
|
||||
addr = 0x01c20848 + 0x00;
|
||||
val = read32(addr);
|
||||
val &= ~(0xf << ((0 & 0x7) << 2));
|
||||
val |= ((0x2 & 0x7) << ((0 & 0x7) << 2));
|
||||
write32(addr, val);
|
||||
|
||||
val = read32(addr);
|
||||
val &= ~(0xf << ((1 & 0x7) << 2));
|
||||
val |= ((0x2 & 0x7) << ((1 & 0x7) << 2));
|
||||
write32(addr, val);
|
||||
|
||||
val = read32(addr);
|
||||
val &= ~(0xf << ((2 & 0x7) << 2));
|
||||
val |= ((0x2 & 0x7) << ((2 & 0x7) << 2));
|
||||
write32(addr, val);
|
||||
|
||||
val = read32(addr);
|
||||
val &= ~(0xf << ((3 & 0x7) << 2));
|
||||
val |= ((0x2 & 0x7) << ((3 & 0x7) << 2));
|
||||
write32(addr, val);
|
||||
|
||||
/* Deassert spi0 reset */
|
||||
addr = 0x01c202c0;
|
||||
val = read32(addr);
|
||||
val |= (1 << 20);
|
||||
write32(addr, val);
|
||||
|
||||
/* Open the spi0 bus gate */
|
||||
addr = 0x01c20000 + 0x60;
|
||||
val = read32(addr);
|
||||
val |= (1 << 20);
|
||||
write32(addr, val);
|
||||
|
||||
/* Set spi clock rate control register, divided by 4 */
|
||||
addr = 0x01c05000;
|
||||
write32(addr + SPI_CCR, 0x00001001);
|
||||
|
||||
/* Enable spi0 and do a soft reset */
|
||||
addr = 0x01c05000;
|
||||
val = read32(addr + SPI_GCR);
|
||||
val |= (1 << 31) | (1 << 7) | (1 << 1) | (1 << 0);
|
||||
write32(addr + SPI_GCR, val);
|
||||
while(read32(addr + SPI_GCR) & (1 << 31));
|
||||
|
||||
val = read32(addr + SPI_TCR);
|
||||
val &= ~(0x3 << 0);
|
||||
val |= (1 << 6) | (1 << 2);
|
||||
write32(addr + SPI_TCR, val);
|
||||
|
||||
val = read32(addr + SPI_FCR);
|
||||
val |= (1 << 31) | (1 << 15);
|
||||
write32(addr + SPI_FCR, val);
|
||||
}
|
||||
|
||||
void sys_spi_flash_exit(void)
|
||||
{
|
||||
virtual_addr_t addr = 0x01c05000;
|
||||
uint32_t val;
|
||||
|
||||
/* Disable the spi0 controller */
|
||||
val = read32(addr + SPI_GCR);
|
||||
val &= ~((1 << 1) | (1 << 0));
|
||||
write32(addr + SPI_GCR, val);
|
||||
}
|
||||
|
||||
static void sys_spi_select(void)
|
||||
{
|
||||
virtual_addr_t addr = 0x01c05000;
|
||||
uint32_t val;
|
||||
|
||||
val = read32(addr + SPI_TCR);
|
||||
val &= ~((0x3 << 4) | (0x1 << 7));
|
||||
val |= ((0 & 0x3) << 4) | (0x0 << 7);
|
||||
write32(addr + SPI_TCR, val);
|
||||
}
|
||||
|
||||
static void sys_spi_deselect(void)
|
||||
{
|
||||
virtual_addr_t addr = 0x01c05000;
|
||||
uint32_t val;
|
||||
|
||||
val = read32(addr + SPI_TCR);
|
||||
val &= ~((0x3 << 4) | (0x1 << 7));
|
||||
val |= ((0 & 0x3) << 4) | (0x1 << 7);
|
||||
write32(addr + SPI_TCR, val);
|
||||
}
|
||||
|
||||
static void sys_spi_write_txbuf(uint8_t * buf, int len)
|
||||
{
|
||||
virtual_addr_t addr = 0x01c05000;
|
||||
int i;
|
||||
|
||||
if(!buf)
|
||||
len = 0;
|
||||
|
||||
write32(addr + SPI_MTC, len & 0xffffff);
|
||||
write32(addr + SPI_BCC, len & 0xffffff);
|
||||
for(i = 0; i < len; ++i)
|
||||
write8(addr + SPI_TXD, *buf++);
|
||||
}
|
||||
|
||||
static int sys_spi_transfer(void * txbuf, void * rxbuf, int len)
|
||||
{
|
||||
virtual_addr_t addr = 0x01c05000;
|
||||
int count = len;
|
||||
uint8_t * tx = txbuf;
|
||||
uint8_t * rx = rxbuf;
|
||||
uint8_t val;
|
||||
unsigned int n, i;
|
||||
|
||||
while(count > 0)
|
||||
{
|
||||
n = (count <= 64) ? count : 64;
|
||||
write32(addr + SPI_MBC, n);
|
||||
sys_spi_write_txbuf(tx, n);
|
||||
write32(addr + SPI_TCR, read32(addr + SPI_TCR) | (1 << 31));
|
||||
|
||||
while((read32(addr + SPI_FSR) & 0xff) < n);
|
||||
for(i = 0; i < n; i++)
|
||||
{
|
||||
val = read8(addr + SPI_RXD);
|
||||
if(rx)
|
||||
*rx++ = val;
|
||||
}
|
||||
|
||||
if(tx)
|
||||
tx += n;
|
||||
count -= n;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
static int sys_spi_write_then_read(void * txbuf, int txlen, void * rxbuf, int rxlen)
|
||||
{
|
||||
if(sys_spi_transfer(txbuf, NULL, txlen) != txlen)
|
||||
return -1;
|
||||
if(sys_spi_transfer(NULL, rxbuf, rxlen) != rxlen)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sys_spi_flash_read(int addr, void * buf, int count)
|
||||
{
|
||||
uint8_t tx[4];
|
||||
|
||||
tx[0] = 0x03;
|
||||
tx[1] = (uint8_t)(addr >> 16);
|
||||
tx[2] = (uint8_t)(addr >> 8);
|
||||
tx[3] = (uint8_t)(addr >> 0);
|
||||
sys_spi_select();
|
||||
sys_spi_write_then_read(tx, 4, buf, count);
|
||||
sys_spi_deselect();
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* sys-uart.c
|
||||
*
|
||||
* Copyright(c) 2007-2018 Jianjun Jiang <8192542@qq.com>
|
||||
* Official site: http://xboot.org
|
||||
* Mobile phone: +86-18665388956
|
||||
* QQ: 8192542
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <types.h>
|
||||
#include <stdint.h>
|
||||
#include <io.h>
|
||||
|
||||
void sys_uart_init(void)
|
||||
{
|
||||
virtual_addr_t addr;
|
||||
uint32_t val;
|
||||
|
||||
/* Config GPIOE1 and GPIOE0 to txd0 and rxd0 */
|
||||
addr = 0x01c20890 + 0x00;
|
||||
val = read32(addr);
|
||||
val &= ~(0xf << ((1 & 0x7) << 2));
|
||||
val |= ((0x5 & 0x7) << ((1 & 0x7) << 2));
|
||||
write32(addr, val);
|
||||
|
||||
val = read32(addr);
|
||||
val &= ~(0xf << ((0 & 0x7) << 2));
|
||||
val |= ((0x5 & 0x7) << ((0 & 0x7) << 2));
|
||||
write32(addr, val);
|
||||
|
||||
/* Open the clock gate for uart0 */
|
||||
addr = 0x01c20068;
|
||||
val = read32(addr);
|
||||
val |= 1 << 20;
|
||||
write32(addr, val);
|
||||
|
||||
/* Deassert uart0 reset */
|
||||
addr = 0x01c202d0;
|
||||
val = read32(addr);
|
||||
val |= 1 << 20;
|
||||
write32(addr, val);
|
||||
|
||||
/* Config uart0 to 115200-8-1-0 */
|
||||
addr = 0x01c25000;
|
||||
write32(addr + 0x04, 0x0);
|
||||
write32(addr + 0x08, 0xf7);
|
||||
write32(addr + 0x10, 0x0);
|
||||
val = read32(addr + 0x0c);
|
||||
val |= (1 << 7);
|
||||
write32(addr + 0x0c, val);
|
||||
write32(addr + 0x00, 0x36 & 0xff);
|
||||
write32(addr + 0x04, (0x36 >> 8) & 0xff);
|
||||
val = read32(addr + 0x0c);
|
||||
val &= ~(1 << 7);
|
||||
write32(addr + 0x0c, val);
|
||||
val = read32(addr + 0x0c);
|
||||
val &= ~0x1f;
|
||||
val |= (0x3 << 0) | (0 << 2) | (0x0 << 3);
|
||||
write32(addr + 0x0c, val);
|
||||
}
|
||||
|
||||
void sys_uart_putc(char c)
|
||||
{
|
||||
virtual_addr_t addr = 0x01c25000;
|
||||
|
||||
while((read32(addr + 0x7c) & (0x1 << 1)) == 0);
|
||||
write32(addr + 0x00, c);
|
||||
}
|
||||
Reference in New Issue
Block a user