Add BSP support for F1C100s

This commit is contained in:
Yunhao Tian
2021-12-04 18:02:07 +08:00
parent dff54d854d
commit 68ca62dfd7
33 changed files with 5043 additions and 2 deletions
@@ -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;
}
}
+313
View File
@@ -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;
}
}
+506
View File
@@ -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(&para))
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);
}