fernvale: Fully get PSRAM working
This uses scriptic to run scripts that do bringup of various systems.
This commit is contained in:
parent
40c1a9941f
commit
555af9447c
17 changed files with 875 additions and 29 deletions
1
Makefile
1
Makefile
|
@ -11,6 +11,7 @@ LIBS =
|
||||||
SRC_C = \
|
SRC_C = \
|
||||||
bionic.c \
|
bionic.c \
|
||||||
cmd-irq.c \
|
cmd-irq.c \
|
||||||
|
emi.c \
|
||||||
irq.c \
|
irq.c \
|
||||||
main.c \
|
main.c \
|
||||||
scriptic.c \
|
scriptic.c \
|
||||||
|
|
149
emi.c
Normal file
149
emi.c
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
#include <string.h>
|
||||||
|
#include "bionic.h"
|
||||||
|
#include "memio.h"
|
||||||
|
|
||||||
|
#include "fernvale-emi.h"
|
||||||
|
#include "fernvale-pmic.h"
|
||||||
|
|
||||||
|
#define PSRAM_TEST_SHOULD_INVERT (1 << 0)
|
||||||
|
#define PSRAM_TEST_SHOULD_RANDOMIZE (1 << 1)
|
||||||
|
|
||||||
|
/* Use the built-in memory self test to check calibration */
|
||||||
|
static int psram_test_run(uint32_t addr, uint32_t length, uint16_t pattern)
|
||||||
|
{
|
||||||
|
int run;
|
||||||
|
uint32_t test_range;
|
||||||
|
uint32_t params;
|
||||||
|
|
||||||
|
test_range = (addr << 8) & 0xffff0000;
|
||||||
|
test_range |= (length >> 8) - 1;
|
||||||
|
|
||||||
|
for (run = 0; run < 4; run++) {
|
||||||
|
/* Params contains the "start key", plus some other flags */
|
||||||
|
params = EMI_CTRL_MBISTB_START_KEY;
|
||||||
|
|
||||||
|
/* On some runs, invert the pattern */
|
||||||
|
if (run & PSRAM_TEST_SHOULD_INVERT)
|
||||||
|
params |= EMI_CTRL_MBISTB_INVERT;
|
||||||
|
|
||||||
|
/* On some runs, randomize the data */
|
||||||
|
if (run & PSRAM_TEST_SHOULD_RANDOMIZE)
|
||||||
|
params |= EMI_CTRL_MBISTB_RANDOMIZE;
|
||||||
|
|
||||||
|
/* Reset MBIST engine */
|
||||||
|
writel(0, EMI_CTRL_MBISTA);
|
||||||
|
|
||||||
|
/* Set range (start and length) */
|
||||||
|
writel(test_range, EMI_CTRL_MBISTB);
|
||||||
|
|
||||||
|
/* Kick off the test */
|
||||||
|
writel(params, EMI_CTRL_MBISTA);
|
||||||
|
|
||||||
|
/* Wait for it to finish */
|
||||||
|
while ( !(readl(EMI_CTRL_MBISTD) & EMI_CTRL_MBISTD_FINISHED) )
|
||||||
|
;
|
||||||
|
|
||||||
|
/* If the test failed, return false */
|
||||||
|
if ( readl(EMI_CTRL_MBISTD) & EMI_CTRL_MBISTD_FAILURE )
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int psram_test(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
uint32_t test_start = 0x100000;
|
||||||
|
uint32_t test_length = 0x8000;
|
||||||
|
|
||||||
|
uint16_t patterns[] = {0xffff, 0xa55a};
|
||||||
|
|
||||||
|
|
||||||
|
for (i = 0; i < sizeof(patterns)/sizeof(*patterns); i++)
|
||||||
|
if (!psram_test_run(test_start, test_length, patterns[i]))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* All tests passed */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set all 16 DQY delays to the same value */
|
||||||
|
static void psram_set_ganged_dqy(uint8_t delay)
|
||||||
|
{
|
||||||
|
uint32_t vals = (delay << 0) |
|
||||||
|
(delay << 8) |
|
||||||
|
(delay << 16) |
|
||||||
|
(delay << 24);
|
||||||
|
writel(vals, EMI_CTRL_IDLA);
|
||||||
|
writel(vals, EMI_CTRL_IDLB);
|
||||||
|
writel(vals, EMI_CTRL_IDLC);
|
||||||
|
writel(vals, EMI_CTRL_IDLD);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void psram_set_ganged_dqs(uint8_t delay)
|
||||||
|
{
|
||||||
|
uint32_t vals = (delay << 24) |
|
||||||
|
(delay << 16);
|
||||||
|
writel(vals, EMI_CTRL_IDLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
int calibrate_psram(void)
|
||||||
|
{
|
||||||
|
int dqy_delay;
|
||||||
|
int dqy_delay_upper = -1;
|
||||||
|
int dqy_delay_lower = -1;
|
||||||
|
|
||||||
|
int dqs_delay;
|
||||||
|
int dqs_delay_upper = -1;
|
||||||
|
int dqs_delay_lower = -1;
|
||||||
|
|
||||||
|
for (dqy_delay = 0; dqy_delay < 32; dqy_delay++) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Since this chip is probably routed properly, assume
|
||||||
|
* all trace lengths require the same delay.
|
||||||
|
*/
|
||||||
|
psram_set_ganged_dqy(dqy_delay);
|
||||||
|
if (psram_test()) {
|
||||||
|
if (dqy_delay_lower == -1)
|
||||||
|
dqy_delay_lower = dqy_delay;
|
||||||
|
else
|
||||||
|
dqy_delay_upper = dqy_delay;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-1 == dqy_delay_upper)
|
||||||
|
dqy_delay_upper = dqy_delay_lower;
|
||||||
|
|
||||||
|
if (dqy_delay_upper != -1) {
|
||||||
|
dqy_delay = (dqy_delay_lower + dqy_delay_upper) / 2;
|
||||||
|
psram_set_ganged_dqy(dqy_delay);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If DQY delays fail, try DQS instead */
|
||||||
|
psram_set_ganged_dqy(0);
|
||||||
|
for (dqs_delay = 1; dqs_delay <= 31; dqs_delay++) {
|
||||||
|
psram_set_ganged_dqs(dqs_delay);
|
||||||
|
if (psram_test()) {
|
||||||
|
if (dqs_delay_lower == -1)
|
||||||
|
dqs_delay_lower = dqs_delay;
|
||||||
|
else
|
||||||
|
dqs_delay_upper = dqs_delay;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-1 == dqs_delay_upper)
|
||||||
|
dqs_delay_upper = dqs_delay_lower;
|
||||||
|
|
||||||
|
if (dqs_delay_upper != -1) {
|
||||||
|
dqs_delay = (dqs_delay_upper + dqs_delay_lower) / 2;
|
||||||
|
psram_set_ganged_dqs(dqs_delay);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Failure */
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -39,7 +39,7 @@ SECTIONS
|
||||||
{
|
{
|
||||||
/* The OS entry point is here */
|
/* The OS entry point is here */
|
||||||
|
|
||||||
. = 0x70000000; /* bootloader will copy data to this address */
|
. = 0x70006000; /* bootloader will copy data to this address */
|
||||||
.text : {
|
.text : {
|
||||||
_stext = ABSOLUTE(.);
|
_stext = ABSOLUTE(.);
|
||||||
KEEP(*(vectors))
|
KEEP(*(vectors))
|
||||||
|
|
96
include/fernvale-emi.h
Normal file
96
include/fernvale-emi.h
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
#ifndef __FV_EMI_H__
|
||||||
|
#define __FV_EMI_H__
|
||||||
|
|
||||||
|
/* Register names based off of:
|
||||||
|
* https://github.com/dragonpt/lenovo_A390_mt6577_uboot_kernel/blob
|
||||||
|
* /master/mediatek/custom
|
||||||
|
* /huaqin77_cu_a510_ics2/preloader/inc/mt6577_emi_reg.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Note: MT6260 has only bank 1 */
|
||||||
|
#define EMI_CTRL_ADDR 0xa0050000
|
||||||
|
#define EMI_CTRL_CONA (EMI_CTRL_ADDR + 0x00) /* Bank 0 control (low) */
|
||||||
|
#define EMI_CTRL_CONB (EMI_CTRL_ADDR + 0x08) /* Bank 1 control (low) */
|
||||||
|
#define EMI_CTRL_CONC (EMI_CTRL_ADDR + 0x10) /* Bank 2 control (low) */
|
||||||
|
#define EMI_CTRL_COND (EMI_CTRL_ADDR + 0x18) /* Bank 3 control (low) */
|
||||||
|
#define EMI_CTRL_CONE (EMI_CTRL_ADDR + 0x20) /* Bank 0 control (high) */
|
||||||
|
#define EMI_CTRL_CONF (EMI_CTRL_ADDR + 0x28) /* Bank 1 control (high) */
|
||||||
|
#define EMI_CTRL_CONG (EMI_CTRL_ADDR + 0x30) /* Bank 2 control (high) */
|
||||||
|
#define EMI_CTRL_CONH (EMI_CTRL_ADDR + 0x38) /* Bank 3 control (high) */
|
||||||
|
#define EMI_CTRL_CONI (EMI_CTRL_ADDR + 0x40) /* Bank 0 control for mDDR */
|
||||||
|
#define EMI_CTRL_CONJ (EMI_CTRL_ADDR + 0x48) /* Bank 1 control for mDDR */
|
||||||
|
#define EMI_CTRL_CONK (EMI_CTRL_ADDR + 0x50) /* Bank 2 control for mDDR */
|
||||||
|
#define EMI_CTRL_CONL (EMI_CTRL_ADDR + 0x58) /* Bank 3 control for mDDR */
|
||||||
|
#define EMI_CTRL_CONM (EMI_CTRL_ADDR + 0x60) /* */
|
||||||
|
#define EMI_CTRL_GENA (EMI_CTRL_ADDR + 0x70) /* General control register 0 */
|
||||||
|
#define EMI_CTRL_GENB (EMI_CTRL_ADDR + 0x78) /* General control register 1 */
|
||||||
|
#define EMI_CTRL_ADMUX (EMI_CTRL_ADDR + 0x80) /* Something involving GPIO mux */
|
||||||
|
#define EMI_CTRL_RDCT (EMI_CTRL_ADDR + 0x88)
|
||||||
|
#define EMI_CTRL_DLLV (EMI_CTRL_ADDR + 0x90)
|
||||||
|
#define EMI_CTRL_IDLA (EMI_CTRL_ADDR + 0xc0)
|
||||||
|
#define EMI_CTRL_IDLB (EMI_CTRL_ADDR + 0xc8)
|
||||||
|
#define EMI_CTRL_IDLC (EMI_CTRL_ADDR + 0xd0)
|
||||||
|
#define EMI_CTRL_IDLD (EMI_CTRL_ADDR + 0xd8)
|
||||||
|
#define EMI_CTRL_IDLE (EMI_CTRL_ADDR + 0xe0)
|
||||||
|
#define EMI_CTRL_ODLA (EMI_CTRL_ADDR + 0xe8)
|
||||||
|
#define EMI_CTRL_ODLB (EMI_CTRL_ADDR + 0xf0)
|
||||||
|
#define EMI_CTRL_ODLC (EMI_CTRL_ADDR + 0xf8)
|
||||||
|
#define EMI_CTRL_ODLD (EMI_CTRL_ADDR + 0x100)
|
||||||
|
#define EMI_CTRL_ODLE (EMI_CTRL_ADDR + 0x108)
|
||||||
|
#define EMI_CTRL_ODLF (EMI_CTRL_ADDR + 0x110)
|
||||||
|
#define EMI_CTRL_IOA (EMI_CTRL_ADDR + 0x130)
|
||||||
|
#define EMI_CTRL_IOB (EMI_CTRL_ADDR + 0x138)
|
||||||
|
#define EMI_CTRL_DSRAM (EMI_CTRL_ADDR + 0x150)
|
||||||
|
#define EMI_CTRL_ARBA (EMI_CTRL_ADDR + 0x170)
|
||||||
|
#define EMI_CTRL_ARBB (EMI_CTRL_ADDR + 0x178)
|
||||||
|
#define EMI_CTRL_ARBC (EMI_CTRL_ADDR + 0x180)
|
||||||
|
#define EMI_CTRL_SLCT (EMI_CTRL_ADDR + 0x198)
|
||||||
|
#define EMI_CTRL_ABCT (EMI_CTRL_ADDR + 0x1a0)
|
||||||
|
#define EMI_CTRL_BMEN (EMI_CTRL_ADDR + 0x200)
|
||||||
|
#define EMI_CTRL_BCNT (EMI_CTRL_ADDR + 0x208)
|
||||||
|
#define EMI_CTRL_TACT (EMI_CTRL_ADDR + 0x210)
|
||||||
|
#define EMI_CTRL_TSCT (EMI_CTRL_ADDR + 0x218)
|
||||||
|
#define EMI_CTRL_WACT (EMI_CTRL_ADDR + 0x220)
|
||||||
|
#define EMI_CTRL_WSCT (EMI_CTRL_ADDR + 0x228)
|
||||||
|
#define EMI_CTRL_BACT (EMI_CTRL_ADDR + 0x230)
|
||||||
|
#define EMI_CTRL_BSCT0 (EMI_CTRL_ADDR + 0x238)
|
||||||
|
#define EMI_CTRL_BSCT1 (EMI_CTRL_ADDR + 0x240)
|
||||||
|
#define EMI_CTRL_TTYPE1 (EMI_CTRL_ADDR + 0x280)
|
||||||
|
#define EMI_CTRL_TTYPE2 (EMI_CTRL_ADDR + 0x288)
|
||||||
|
#define EMI_CTRL_TTYPE3 (EMI_CTRL_ADDR + 0x290)
|
||||||
|
#define EMI_CTRL_TTYPE4 (EMI_CTRL_ADDR + 0x298)
|
||||||
|
#define EMI_CTRL_TTYPE5 (EMI_CTRL_ADDR + 0x2a0)
|
||||||
|
#define EMI_CTRL_TTYPE6 (EMI_CTRL_ADDR + 0x2a8)
|
||||||
|
#define EMI_CTRL_TTYPE7 (EMI_CTRL_ADDR + 0x2b0)
|
||||||
|
#define EMI_CTRL_TTYPE8 (EMI_CTRL_ADDR + 0x2b8)
|
||||||
|
#define EMI_CTRL_TTYPE9 (EMI_CTRL_ADDR + 0x2c0)
|
||||||
|
#define EMI_CTRL_TTYPE10 (EMI_CTRL_ADDR + 0x2c8)
|
||||||
|
#define EMI_CTRL_TTYPE11 (EMI_CTRL_ADDR + 0x2d0)
|
||||||
|
#define EMI_CTRL_TTYPE12 (EMI_CTRL_ADDR + 0x2d8)
|
||||||
|
#define EMI_CTRL_TTYPE13 (EMI_CTRL_ADDR + 0x2e0)
|
||||||
|
#define EMI_CTRL_TTYPE14 (EMI_CTRL_ADDR + 0x2e8)
|
||||||
|
#define EMI_CTRL_TTYPE15 (EMI_CTRL_ADDR + 0x2f0)
|
||||||
|
#define EMI_CTRL_TTYPE16 (EMI_CTRL_ADDR + 0x2f8)
|
||||||
|
|
||||||
|
#define EMI_CTRL_MBISTA (EMI_CTRL_ADDR + 0x300)
|
||||||
|
#define EMI_CTRL_MBISTA_PATTERN_SHIFT 16
|
||||||
|
#define EMI_CTRL_MBISTA_PATTERN_MASK 0xffff0000
|
||||||
|
|
||||||
|
#define EMI_CTRL_MBISTB (EMI_CTRL_ADDR + 0x308)
|
||||||
|
#define EMI_CTRL_MBISTB_START_KEY 0x325
|
||||||
|
#define EMI_CTRL_MBISTB_RANDOMIZE (1 << 12)
|
||||||
|
#define EMI_CTRL_MBISTB_INVERT (1 << 13)
|
||||||
|
|
||||||
|
#define EMI_CTRL_MBISTC (EMI_CTRL_ADDR + 0x310)
|
||||||
|
|
||||||
|
#define EMI_CTRL_MBISTD (EMI_CTRL_ADDR + 0x318)
|
||||||
|
#define EMI_CTRL_MBISTD_FAILURE (1 << 0)
|
||||||
|
#define EMI_CTRL_MBISTD_FINISHED (1 << 1)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define EMI_CTRL_TEST (EMI_CTRL_ADDR + 0x330)
|
||||||
|
|
||||||
|
#define EMI_CTRL_REMAP (0xA0510000)
|
||||||
|
|
||||||
|
#endif /* __FV_EMI_H__ */
|
72
include/fernvale-pll.h
Normal file
72
include/fernvale-pll.h
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
#ifndef __FV_PLL_H__
|
||||||
|
#define __FV_PLL_H__
|
||||||
|
|
||||||
|
/* Register names and values adapted from:
|
||||||
|
* https://github.com/wiko-sources/cink-slim/blob
|
||||||
|
* /master/mediatek/platform/mt6577
|
||||||
|
* /kernel/core/include/mach/mt6577_clock_manager.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define PLL_CTRL_ADDR 0xa0170000
|
||||||
|
#define PLL_CLK_ADDR 0x80000100
|
||||||
|
|
||||||
|
#define PLL_CTRL_XOSC_CON0 (PLL_CTRL_ADDR + 0x00)
|
||||||
|
#define PLL_CTRL_XOSC_CON1 (PLL_CTRL_ADDR + 0x04)
|
||||||
|
|
||||||
|
#define PLL_CTRL_CLKSQ_CON0 (PLL_CTRL_ADDR + 0x20)
|
||||||
|
#define PLL_CTRL_CLKSQ_CON1 (PLL_CTRL_ADDR + 0x24)
|
||||||
|
#define PLL_CTRL_CLKSQ_CON2 (PLL_CTRL_ADDR + 0x28)
|
||||||
|
|
||||||
|
#define PLL_CTRL_CON0 (PLL_CTRL_ADDR + 0x40)
|
||||||
|
#define PLL_CTRL_CON1 (PLL_CTRL_ADDR + 0x44)
|
||||||
|
#define PLL_CTRL_CON2 (PLL_CTRL_ADDR + 0x48)
|
||||||
|
#define PLL_CTRL_CON3 (PLL_CTRL_ADDR + 0x4c)
|
||||||
|
#define PLL_CTRL_CON4 (PLL_CTRL_ADDR + 0x50)
|
||||||
|
#define PLL_CTRL_CON5 (PLL_CTRL_ADDR + 0x54)
|
||||||
|
#define PLL_CTRL_CON6 (PLL_CTRL_ADDR + 0x58)
|
||||||
|
#define PLL_CTRL_CON7 (PLL_CTRL_ADDR + 0x5c)
|
||||||
|
#define PLL_CTRL_CON8 (PLL_CTRL_ADDR + 0x5c)
|
||||||
|
#define PLL_CTRL_CON9 (PLL_CTRL_ADDR + 0x5c)
|
||||||
|
#define PLL_CTRL_CON10 (PLL_CTRL_ADDR + 0x5c)
|
||||||
|
#define PLL_CTRL_CON11 (PLL_CTRL_ADDR + 0x5c)
|
||||||
|
|
||||||
|
#define PLL_CTRL_DPM_CON0 (PLL_CTRL_ADDR + 0x90)
|
||||||
|
#define PLL_CTRL_DPM_CON1 (PLL_CTRL_ADDR + 0x94)
|
||||||
|
#define PLL_CTRL_DPM_CON2 (PLL_CTRL_ADDR + 0x98)
|
||||||
|
|
||||||
|
#define PLL_CTRL_MPLL_CON0 (PLL_CTRL_ADDR + 0x100)
|
||||||
|
#define PLL_CTRL_MPLL_CON1 (PLL_CTRL_ADDR + 0x104)
|
||||||
|
#define PLL_CTRL_MPLL_CON2 (PLL_CTRL_ADDR + 0x108)
|
||||||
|
|
||||||
|
#define PLL_CTRL_UPLL_CON0 (PLL_CTRL_ADDR + 0x140)
|
||||||
|
#define PLL_CTRL_UPLL_CON1 (PLL_CTRL_ADDR + 0x144)
|
||||||
|
#define PLL_CTRL_UPLL_CON2 (PLL_CTRL_ADDR + 0x148)
|
||||||
|
|
||||||
|
#define PLL_CTRL_EPLL_CON0 (PLL_CTRL_ADDR + 0x180)
|
||||||
|
#define PLL_CTRL_EPLL_CON1 (PLL_CTRL_ADDR + 0x184)
|
||||||
|
#define PLL_CTRL_EPLL_CON2 (PLL_CTRL_ADDR + 0x188)
|
||||||
|
|
||||||
|
#define PLL_CTRL_FH_CON0 (PLL_CTRL_ADDR + 0x500)
|
||||||
|
#define PLL_CTRL_FH_CON1 (PLL_CTRL_ADDR + 0x504)
|
||||||
|
#define PLL_CTRL_FH_CON2 (PLL_CTRL_ADDR + 0x508)
|
||||||
|
#define PLL_CTRL_FH_CON3 (PLL_CTRL_ADDR + 0x50c)
|
||||||
|
#define PLL_CTRL_FH_CON4 (PLL_CTRL_ADDR + 0x510)
|
||||||
|
|
||||||
|
#define PLL_CTRL_MDDS_CON0 (PLL_CTRL_ADDR + 0x640)
|
||||||
|
#define PLL_CTRL_MDDS_CON1 (PLL_CTRL_ADDR + 0x644)
|
||||||
|
#define PLL_CTRL_MDDS_CON2 (PLL_CTRL_ADDR + 0x648)
|
||||||
|
|
||||||
|
#define PLL_CTRL_EDDS_CON0 (PLL_CTRL_ADDR + 0x680)
|
||||||
|
#define PLL_CTRL_EDDS_CON1 (PLL_CTRL_ADDR + 0x684)
|
||||||
|
#define PLL_CTRL_EDDS_CON2 (PLL_CTRL_ADDR + 0x688)
|
||||||
|
|
||||||
|
#define PLL_CTRL_CLK_CONDA (PLL_CLK_ADDR + 0x00)
|
||||||
|
#define PLL_CTRL_CLK_CONDB (PLL_CLK_ADDR + 0x04)
|
||||||
|
#define PLL_CTRL_CLK_CONDC (PLL_CLK_ADDR + 0x08)
|
||||||
|
#define PLL_CTRL_CLK_CONDD (PLL_CLK_ADDR + 0x0c)
|
||||||
|
#define PLL_CTRL_CLK_CONDE (PLL_CLK_ADDR + 0x10)
|
||||||
|
#define PLL_CTRL_CLK_CONDF (PLL_CLK_ADDR + 0x14)
|
||||||
|
#define PLL_CTRL_CLK_CONDG (PLL_CLK_ADDR + 0x18)
|
||||||
|
#define PLL_CTRL_CLK_CONDH (PLL_CLK_ADDR + 0x1c)
|
||||||
|
|
||||||
|
#endif /* __FV_PLL_H__ */
|
17
include/fernvale-pmic.h
Normal file
17
include/fernvale-pmic.h
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
#ifndef __FV_PMIC_H__
|
||||||
|
#define __FV_PMIC_H__
|
||||||
|
|
||||||
|
#define PMIC_ADDR 0xa0700a00
|
||||||
|
#define PMIC_CTRL0 (PMIC_ADDR + 0x00)
|
||||||
|
#define PMIC_CTRL1 (PMIC_ADDR + 0x04)
|
||||||
|
#define PMIC_CTRL2 (PMIC_ADDR + 0x08)
|
||||||
|
#define PMIC_CTRL3 (PMIC_ADDR + 0x0c)
|
||||||
|
#define PMIC_CTRL4 (PMIC_ADDR + 0x10)
|
||||||
|
#define PMIC_CTRL5 (PMIC_ADDR + 0x14)
|
||||||
|
#define PMIC_CTRL6 (PMIC_ADDR + 0x18)
|
||||||
|
#define PMIC_CTRL7 (PMIC_ADDR + 0x1c)
|
||||||
|
#define PMIC_CTRL8 (PMIC_ADDR + 0x20)
|
||||||
|
#define PMIC_CTRL9 (PMIC_ADDR + 0x24)
|
||||||
|
#define PMIC_CTRL10 (PMIC_ADDR + 0x28)
|
||||||
|
|
||||||
|
#endif /* __FV_PMIC_H__ */
|
|
@ -1,35 +1,35 @@
|
||||||
#ifndef __MEMIO_H__
|
#ifndef __FV_MEMIO_H__
|
||||||
#define __MEMIO_H__
|
#define __FV_MEMIO_H__
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
inline void writeb(uint8_t value, uint32_t addr)
|
static inline void writeb(uint8_t value, uint32_t addr)
|
||||||
{
|
{
|
||||||
*((volatile uint8_t *)addr) = value;
|
*((volatile uint8_t *)addr) = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint8_t readb(uint32_t addr)
|
static inline uint8_t readb(uint32_t addr)
|
||||||
{
|
{
|
||||||
return *(volatile uint8_t *)addr;
|
return *(volatile uint8_t *)addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void writew(uint16_t value, uint32_t addr)
|
static inline void writew(uint16_t value, uint32_t addr)
|
||||||
{
|
{
|
||||||
*((volatile uint16_t *)addr) = value;
|
*((volatile uint16_t *)addr) = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint16_t readw(uint32_t addr)
|
static inline uint16_t readw(uint32_t addr)
|
||||||
{
|
{
|
||||||
return *(volatile uint16_t *)addr;
|
return *(volatile uint16_t *)addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void writel(uint32_t value, uint32_t addr)
|
static inline void writel(uint32_t value, uint32_t addr)
|
||||||
{
|
{
|
||||||
*((volatile uint32_t *)addr) = value;
|
*((volatile uint32_t *)addr) = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint32_t readl(uint32_t addr)
|
static inline uint32_t readl(uint32_t addr)
|
||||||
{
|
{
|
||||||
return *(volatile uint32_t *)addr;
|
return *(volatile uint32_t *)addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* __MEMIO_H__ */
|
#endif /* __FV_MEMIO_H__ */
|
||||||
|
|
170
include/scriptic.h
Normal file
170
include/scriptic.h
Normal file
|
@ -0,0 +1,170 @@
|
||||||
|
#ifndef __SCRIPTIC_H__
|
||||||
|
#define __SCRIPTIC_H__
|
||||||
|
|
||||||
|
#define sc_end_cmd 0
|
||||||
|
#define sc_read32_cmd 1
|
||||||
|
#define sc_write32_cmd 2
|
||||||
|
#define sc_read16_cmd 3
|
||||||
|
#define sc_write16_cmd 4
|
||||||
|
#define sc_call_cmd 5
|
||||||
|
#define sc_usleep_cmd 6
|
||||||
|
|
||||||
|
#define sc_header_size (4 * 2)
|
||||||
|
#define sc_end_size (sc_header_size + 0)
|
||||||
|
#define sc_read32_size (sc_header_size + 4 * 3)
|
||||||
|
#define sc_write32_size (sc_header_size + 4 * 3)
|
||||||
|
#define sc_read16_size (sc_header_size + 4 * 2 + 1 * 4)
|
||||||
|
#define sc_write16_size (sc_header_size + 4 * 2 + 1 * 4)
|
||||||
|
#define sc_call_size (sc_header_size + 4 * 2)
|
||||||
|
#define sc_usleep_size (sc_header_size + 4 * 1)
|
||||||
|
|
||||||
|
#ifdef __ASSEMBLY__
|
||||||
|
|
||||||
|
.macro sc_header cmd
|
||||||
|
@cmdindex=@cmdindex+1
|
||||||
|
.long \cmd
|
||||||
|
.long 0 @cmdindex
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro sc_end
|
||||||
|
sc_header sc_end_cmd
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro sc_read32 match, mask, addr
|
||||||
|
sc_header sc_read32_cmd
|
||||||
|
.long \match
|
||||||
|
.long \mask
|
||||||
|
.long \addr
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro sc_write32 value, mask, addr
|
||||||
|
sc_header sc_write32_cmd
|
||||||
|
.long \value
|
||||||
|
.long \mask
|
||||||
|
.long \addr
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro sc_read16 match, mask, addr
|
||||||
|
sc_header sc_read16_cmd
|
||||||
|
.short \match
|
||||||
|
.short \mask
|
||||||
|
.long \addr
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro sc_write16 value, mask, addr
|
||||||
|
sc_header sc_write16_cmd
|
||||||
|
.short \value
|
||||||
|
.short \mask
|
||||||
|
.long \addr
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro sc_call func, arg
|
||||||
|
sc_header sc_call_cmd
|
||||||
|
.long \func
|
||||||
|
.long \arg
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro sc_usleep microsecs
|
||||||
|
sc_header sc_usleep_cmd
|
||||||
|
.long \microsecs
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro sc_new name, major, minor, rev
|
||||||
|
.align 4
|
||||||
|
.global \name
|
||||||
|
@cmdindex=0 // Reset command index counter variable
|
||||||
|
\name:
|
||||||
|
1:
|
||||||
|
.asciz "\name"
|
||||||
|
2:
|
||||||
|
.iflt 16 - (2b - 1b)
|
||||||
|
.error "Name too long (16-bytes max)"
|
||||||
|
.endif
|
||||||
|
|
||||||
|
// Zero-pad
|
||||||
|
.ifgt 16 - (2b - 1b)
|
||||||
|
.zero 16 - (2b - 1b)
|
||||||
|
.endif
|
||||||
|
|
||||||
|
.byte \major // ver_major
|
||||||
|
.byte \minor // ver_minor
|
||||||
|
.short \rev // ver_rev
|
||||||
|
.long 0 // command_count
|
||||||
|
// Commands will follow in RAM
|
||||||
|
.endm
|
||||||
|
|
||||||
|
#else /* ! __ASSEMBLY__ */
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/* Header prefixed in all commands */
|
||||||
|
struct scriptic_header {
|
||||||
|
uint32_t command;
|
||||||
|
uint32_t index;
|
||||||
|
} __attribute__((__packed__));
|
||||||
|
|
||||||
|
/* Stop execution */
|
||||||
|
struct scriptic_end {
|
||||||
|
struct scriptic_header header;
|
||||||
|
} __attribute__((__packed__));
|
||||||
|
|
||||||
|
/* Read 32-bit value (and optionally wait for a value) */
|
||||||
|
struct scriptic_read32 {
|
||||||
|
struct scriptic_header header;
|
||||||
|
uint32_t match; /* Value to match */
|
||||||
|
uint32_t mask; /* Mask for bits to match */
|
||||||
|
uint32_t addr; /* Address to read from */
|
||||||
|
} __attribute__((__packed__));
|
||||||
|
|
||||||
|
/* Write a 32-bit value to an address */
|
||||||
|
struct scriptic_write32 {
|
||||||
|
struct scriptic_header header;
|
||||||
|
uint32_t value; /* Value to write */
|
||||||
|
uint32_t mask; /* Mask for bits to write */
|
||||||
|
uint32_t addr; /* Address to write to */
|
||||||
|
} __attribute__((__packed__));
|
||||||
|
|
||||||
|
/* Read 16-bit value (and optionally wait for a value) */
|
||||||
|
struct scriptic_read16 {
|
||||||
|
struct scriptic_header header;
|
||||||
|
uint16_t match; /* Value to match */
|
||||||
|
uint16_t mask; /* Mask for bits to match */
|
||||||
|
uint32_t addr; /* Address to read from */
|
||||||
|
} __attribute__((__packed__));
|
||||||
|
|
||||||
|
/* Write a 16-bit value to an address */
|
||||||
|
struct scriptic_write16 {
|
||||||
|
struct scriptic_header header;
|
||||||
|
uint16_t value; /* Value to write */
|
||||||
|
uint16_t mask; /* Mask for bits to write */
|
||||||
|
uint32_t addr; /* Address to write to */
|
||||||
|
} __attribute__((__packed__));
|
||||||
|
|
||||||
|
/* Call a function repeatedly and wait for it to return true */
|
||||||
|
struct scriptic_call {
|
||||||
|
struct scriptic_header header;
|
||||||
|
int (*func)(void *arg); /* Function to call */
|
||||||
|
void *opaque; /* Arg to pass */
|
||||||
|
} __attribute__((__packed__));
|
||||||
|
|
||||||
|
/* Sleep for a given number of microseconds */
|
||||||
|
struct scriptic_usleep {
|
||||||
|
struct scriptic_header header;
|
||||||
|
uint32_t usecs; /* Number of microseconds */
|
||||||
|
} __attribute__((__packed__));
|
||||||
|
|
||||||
|
struct scriptic {
|
||||||
|
const char name[16];
|
||||||
|
uint8_t ver_major;
|
||||||
|
uint8_t ver_minor;
|
||||||
|
uint16_t ver_rev;
|
||||||
|
uint32_t command_count;
|
||||||
|
} __attribute__((__packed__));
|
||||||
|
|
||||||
|
int scriptic_execute(const struct scriptic *script);
|
||||||
|
const struct scriptic *scriptic_get(const char *name);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* __ASSEMBLY__ */
|
||||||
|
|
||||||
|
#endif /* __SCRIPTIC_H__ */
|
7
include/spi.h
Normal file
7
include/spi.h
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
|
||||||
|
#ifndef __SPI_H__
|
||||||
|
#define __SPI_H__
|
||||||
|
|
||||||
|
#define SPI_ADDR 0xa0140000
|
||||||
|
|
||||||
|
#endif /* __SPI_H__ */
|
|
@ -2,6 +2,19 @@
|
||||||
#define __UTILS_H__
|
#define __UTILS_H__
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
# define do_div(n,base) ({ \
|
||||||
|
uint32_t __base = (base); \
|
||||||
|
uint32_t __rem; \
|
||||||
|
(void)(((typeof((n)) *)0) == ((uint64_t *)0)); \
|
||||||
|
if (((n) >> 32) == 0) { \
|
||||||
|
__rem = (uint32_t)(n) % __base; \
|
||||||
|
(n) = (uint32_t)(n) / __base; \
|
||||||
|
} else \
|
||||||
|
__rem = __div64_32(&(n), __base); \
|
||||||
|
__rem; \
|
||||||
|
})
|
||||||
|
|
||||||
uint32_t _udiv64(uint64_t n, uint32_t d);
|
uint32_t _udiv64(uint64_t n, uint32_t d);
|
||||||
|
uint32_t __div64_32(uint64_t *n, uint32_t base);
|
||||||
|
|
||||||
#endif /* __UTILS_H__ */
|
#endif /* __UTILS_H__ */
|
||||||
|
|
2
magic.mk
2
magic.mk
|
@ -17,7 +17,7 @@
|
||||||
vpath %.S . $(TOP)
|
vpath %.S . $(TOP)
|
||||||
$(BUILD)/%.o: %.S
|
$(BUILD)/%.o: %.S
|
||||||
$(ECHO) "CC $<"
|
$(ECHO) "CC $<"
|
||||||
$(Q)$(CC) $(CFLAGS) -c -o $@ $<
|
$(Q)$(CC) $(CFLAGS) $(AFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
vpath %.s . $(TOP)
|
vpath %.s . $(TOP)
|
||||||
$(BUILD)/%.o: %.s
|
$(BUILD)/%.o: %.s
|
||||||
|
|
26
main.c
26
main.c
|
@ -4,6 +4,9 @@
|
||||||
#include "printf.h"
|
#include "printf.h"
|
||||||
#include "serial.h"
|
#include "serial.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
#include "scriptic.h"
|
||||||
|
|
||||||
|
#include "fernvale-pmic.h"
|
||||||
|
|
||||||
//#define AUTOMATED
|
//#define AUTOMATED
|
||||||
|
|
||||||
|
@ -193,34 +196,27 @@ static int list_registers(void)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define PMIC_BASE 0xa0700a00
|
|
||||||
#define PMIC_CTRL0 (PMIC_BASE + 0x04)
|
|
||||||
#define PMIC_CTRL1 (PMIC_BASE + 0x04)
|
|
||||||
#define PMIC_CTRL2 (PMIC_BASE + 0x08)
|
|
||||||
#define PMIC_CTRL3 (PMIC_BASE + 0x0c)
|
|
||||||
#define PMIC_CTRL4 (PMIC_BASE + 0x10)
|
|
||||||
#define PMIC_CTRL5 (PMIC_BASE + 0x14)
|
|
||||||
#define PMIC_CTRL6 (PMIC_BASE + 0x18)
|
|
||||||
#define PMIC_CTRL7 (PMIC_BASE + 0x1c)
|
|
||||||
#define PMIC_CTRL8 (PMIC_BASE + 0x20)
|
|
||||||
#define PMIC_CTRL9 (PMIC_BASE + 0x24)
|
|
||||||
#define PMIC_CTRL10 (PMIC_BASE + 0x28)
|
|
||||||
|
|
||||||
static int do_init(void)
|
static int do_init(void)
|
||||||
{
|
{
|
||||||
|
const struct scriptic *script;
|
||||||
|
|
||||||
list_registers();
|
list_registers();
|
||||||
|
|
||||||
/* Disable system watchdog */
|
/* Disable system watchdog */
|
||||||
writel(0x2200, 0xa0030000);
|
writel(0x2200, 0xa0030000);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Enable USB Download mode (required for no-battery operation) */
|
/* Enable USB Download mode (required for no-battery operation) */
|
||||||
writew(0x8000, PMIC_CTRL10);
|
writew(0x8000, PMIC_CTRL10);
|
||||||
|
|
||||||
/* Disable battery watchdog */
|
/* Disable battery watchdog */
|
||||||
writew(0x2, PMIC_CTRL9);
|
writew(0x2, PMIC_CTRL9);
|
||||||
|
|
||||||
|
script = scriptic_get("set_plls");
|
||||||
|
scriptic_execute(script);
|
||||||
|
|
||||||
|
script = scriptic_get("enable_psram");
|
||||||
|
scriptic_execute(script);
|
||||||
|
|
||||||
serial_puts("\n\nFernly shell\n");
|
serial_puts("\n\nFernly shell\n");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
183
scriptic.c
Normal file
183
scriptic.c
Normal file
|
@ -0,0 +1,183 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "scriptic.h"
|
||||||
|
#include "bionic.h"
|
||||||
|
#include "memio.h"
|
||||||
|
|
||||||
|
extern struct scriptic set_plls;
|
||||||
|
extern struct scriptic enable_psram;
|
||||||
|
|
||||||
|
static int sc_header_command(struct scriptic_header *header)
|
||||||
|
{
|
||||||
|
return header->command;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sc_command_size(void *header) {
|
||||||
|
switch(sc_header_command(header)) {
|
||||||
|
case sc_end_cmd: return sizeof(struct scriptic_end);
|
||||||
|
case sc_read32_cmd: return sizeof(struct scriptic_read32);
|
||||||
|
case sc_write32_cmd: return sizeof(struct scriptic_write32);
|
||||||
|
case sc_read16_cmd: return sizeof(struct scriptic_read16);
|
||||||
|
case sc_write16_cmd: return sizeof(struct scriptic_write16);
|
||||||
|
case sc_call_cmd: return sizeof(struct scriptic_call);
|
||||||
|
case sc_usleep_cmd: return sizeof(struct scriptic_usleep);
|
||||||
|
default: return sizeof(struct scriptic_header);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct scriptic_header *sc_next_command(void *header)
|
||||||
|
{
|
||||||
|
return header + sc_command_size(header);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sc_command_count(struct scriptic *script)
|
||||||
|
{
|
||||||
|
uint32_t count = 1;
|
||||||
|
struct scriptic_header *header = (struct scriptic_header *)&script[1];
|
||||||
|
|
||||||
|
for (count = 0; sc_header_command(header) != sc_end_cmd; count++) {
|
||||||
|
header->index = count;
|
||||||
|
header = sc_next_command(header);
|
||||||
|
}
|
||||||
|
header->index = count;
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Command functions */
|
||||||
|
|
||||||
|
static void sc_read32(struct scriptic_read32 *pkt)
|
||||||
|
{
|
||||||
|
if ((pkt->mask == 0) || (pkt->mask == 0xffffffff))
|
||||||
|
(void)readl(pkt->addr);
|
||||||
|
else {
|
||||||
|
while (1) {
|
||||||
|
uint32_t val = readl(pkt->addr);
|
||||||
|
if ((val & pkt->mask) == (pkt->match & pkt->mask) )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sc_read16(struct scriptic_read16 *pkt)
|
||||||
|
{
|
||||||
|
if ((pkt->mask == 0) || (pkt->mask == 0xffff))
|
||||||
|
(void)readw(pkt->addr);
|
||||||
|
else
|
||||||
|
while (1) {
|
||||||
|
uint16_t val = readw(pkt->addr);
|
||||||
|
if ((val & pkt->mask) == (pkt->match & pkt->mask) )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sc_write32(struct scriptic_write32 *pkt)
|
||||||
|
{
|
||||||
|
if ((pkt->mask == 0) || (pkt->mask == 0xffffffff)) {
|
||||||
|
writel(pkt->value, pkt->addr);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
uint32_t tmp;
|
||||||
|
tmp = readl(pkt->addr);
|
||||||
|
tmp &= ~pkt->mask;
|
||||||
|
tmp |= (pkt->value & pkt->mask);
|
||||||
|
writel(tmp, pkt->addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sc_write16(struct scriptic_write16 *pkt)
|
||||||
|
{
|
||||||
|
if ((pkt->mask == 0) || (pkt->mask == 0xffff)) {
|
||||||
|
writew(pkt->value, pkt->addr);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
uint16_t tmp;
|
||||||
|
tmp = readw(pkt->addr);
|
||||||
|
tmp &= ~pkt->mask;
|
||||||
|
tmp |= (pkt->value & pkt->mask);
|
||||||
|
writew(tmp, pkt->addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sc_call(struct scriptic_call *pkt)
|
||||||
|
{
|
||||||
|
while (!pkt->func(pkt->opaque));
|
||||||
|
}
|
||||||
|
|
||||||
|
void sc_usleep(struct scriptic_usleep *pkt)
|
||||||
|
{
|
||||||
|
uint32_t usecs;
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
usecs = pkt->usecs;
|
||||||
|
|
||||||
|
/* Outer loop is 11 cycles total, 6 cycles on its own */
|
||||||
|
for (i = 0; i < usecs; i++)
|
||||||
|
/* Inner loop is 5 cycles */
|
||||||
|
for (j = 0; j < 73; j++)
|
||||||
|
asm("nop");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Exported functions */
|
||||||
|
|
||||||
|
int scriptic_execute(const struct scriptic *script)
|
||||||
|
{
|
||||||
|
void *header;
|
||||||
|
|
||||||
|
if (!script)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
header = (struct scriptic_header *)&script[1];
|
||||||
|
|
||||||
|
while (sc_header_command(header) != sc_end_cmd) {
|
||||||
|
switch(sc_header_command(header)) {
|
||||||
|
case sc_end_cmd:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case sc_read32_cmd:
|
||||||
|
sc_read32(header);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case sc_write32_cmd:
|
||||||
|
sc_write32(header);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case sc_read16_cmd:
|
||||||
|
sc_read16(header);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case sc_write16_cmd:
|
||||||
|
sc_write16(header);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case sc_call_cmd:
|
||||||
|
sc_call(header);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case sc_usleep_cmd:
|
||||||
|
sc_usleep(header);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
header = sc_next_command(header);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct scriptic *scriptic_get(const char *name)
|
||||||
|
{
|
||||||
|
struct scriptic *script = NULL;
|
||||||
|
|
||||||
|
if (!_strcasecmp(name, "set_plls"))
|
||||||
|
script = &set_plls;
|
||||||
|
else if (!_strcasecmp(name, "enable_psram"))
|
||||||
|
script = &enable_psram;
|
||||||
|
|
||||||
|
if (script && script->command_count == 0)
|
||||||
|
script->command_count = sc_command_count(script);
|
||||||
|
|
||||||
|
return script;
|
||||||
|
}
|
74
scriptic/enable-psram.S
Normal file
74
scriptic/enable-psram.S
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
#include "scriptic.h"
|
||||||
|
#include "fernvale-emi.h"
|
||||||
|
|
||||||
|
sc_new "enable_psram", 1, 0, 0
|
||||||
|
|
||||||
|
sc_write32 0x401, 0, EMI_CTRL_GENA
|
||||||
|
|
||||||
|
/* Remap EMI to 0x10000000, and SPI to 0x00000000 */
|
||||||
|
sc_write32 2, 0, EMI_CTRL_REMAP
|
||||||
|
|
||||||
|
/* Memory configuration */
|
||||||
|
sc_read16 0, 0, 0x1ffffffe
|
||||||
|
sc_usleep 50
|
||||||
|
sc_read16 0, 0, 0x1ffffffe
|
||||||
|
sc_usleep 50
|
||||||
|
|
||||||
|
sc_write16 1, 0, 0x1ffffffe
|
||||||
|
sc_usleep 50
|
||||||
|
sc_write16 0x2b13, 0, 0x1ffffffe
|
||||||
|
sc_usleep 50
|
||||||
|
|
||||||
|
sc_read16 0, 0, 0x1ffffffe
|
||||||
|
sc_usleep 50
|
||||||
|
sc_read16 0, 0, 0x1ffffffe
|
||||||
|
sc_usleep 50
|
||||||
|
|
||||||
|
sc_write16 0, 0, 0x1ffffffe
|
||||||
|
sc_usleep 50
|
||||||
|
sc_write16 0x10, 0, 0x1ffffffe
|
||||||
|
sc_usleep 50
|
||||||
|
|
||||||
|
sc_write32 0xa0000000, 0, EMI_CTRL_CONB
|
||||||
|
sc_write32 0xb2024419, 0, EMI_CTRL_CONF
|
||||||
|
sc_usleep 50
|
||||||
|
|
||||||
|
sc_write32 0x400, 0x400, EMI_CTRL_GENA
|
||||||
|
|
||||||
|
/* Now map EMI back to 0x00000000, and SPI to 0x00000000 */
|
||||||
|
sc_write32 3, 0, EMI_CTRL_REMAP
|
||||||
|
sc_usleep 50
|
||||||
|
|
||||||
|
sc_write32 0x20004001, 0, EMI_CTRL_RDCT
|
||||||
|
sc_write32 0x5111, 0, EMI_CTRL_DSRAM
|
||||||
|
|
||||||
|
sc_write32 0, 0, EMI_CTRL_IDLA
|
||||||
|
sc_write32 0, 0, EMI_CTRL_IDLB
|
||||||
|
sc_write32 0, 0, EMI_CTRL_IDLC
|
||||||
|
sc_write32 0, 0, EMI_CTRL_IDLD
|
||||||
|
sc_write32 0, 0, EMI_CTRL_IDLE
|
||||||
|
sc_write32 0, 0, EMI_CTRL_ODLA
|
||||||
|
sc_write32 0, 0, EMI_CTRL_ODLB
|
||||||
|
sc_write32 0, 0, EMI_CTRL_ODLC
|
||||||
|
sc_write32 0, 0, EMI_CTRL_ODLD
|
||||||
|
sc_write32 0, 0, EMI_CTRL_ODLE
|
||||||
|
|
||||||
|
sc_write32 0x00010001, 0, EMI_CTRL_IOA
|
||||||
|
sc_write32 0x00010001, 0, EMI_CTRL_IOB
|
||||||
|
|
||||||
|
sc_usleep 50
|
||||||
|
|
||||||
|
/* Calibrate DQ in delay */
|
||||||
|
sc_call calibrate_psram, 0
|
||||||
|
|
||||||
|
sc_write32 0x300f0000, 0, EMI_CTRL_DLLV
|
||||||
|
sc_read32 0x80, 0x80, EMI_CTRL_DLLV
|
||||||
|
sc_write32 0x700f0000, 0, EMI_CTRL_DLLV
|
||||||
|
sc_read32 0x80, 0x00, EMI_CTRL_DLLV
|
||||||
|
sc_write32 0x100f0000, 0, EMI_CTRL_DLLV
|
||||||
|
|
||||||
|
sc_write32 0x5426, 0, EMI_CTRL_ARBA
|
||||||
|
sc_write32 0x5009, 0, EMI_CTRL_ARBB
|
||||||
|
sc_write32 0x5051, 0, EMI_CTRL_ARBC
|
||||||
|
|
||||||
|
sc_end
|
29
scriptic/set-plls.S
Normal file
29
scriptic/set-plls.S
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
#include "scriptic.h"
|
||||||
|
#include "fernvale-pll.h"
|
||||||
|
|
||||||
|
sc_new "set_plls", 1, 0, 0
|
||||||
|
|
||||||
|
sc_write16 0, 0, PLL_CTRL_CON2
|
||||||
|
sc_write16 0, 0, PLL_CTRL_CON3
|
||||||
|
sc_write16 0, 0, PLL_CTRL_CON0
|
||||||
|
sc_usleep 1
|
||||||
|
|
||||||
|
sc_write16 1, 1, PLL_CTRL_UPLL_CON0
|
||||||
|
sc_write16 0x1840, 0, PLL_CTRL_EPLL_CON0
|
||||||
|
sc_write16 0x100, 0x100, PLL_CTRL_EPLL_CON1
|
||||||
|
sc_write16 1, 0, PLL_CTRL_MDDS_CON0
|
||||||
|
sc_write16 1, 1, PLL_CTRL_MPLL_CON0
|
||||||
|
sc_usleep 1
|
||||||
|
|
||||||
|
sc_write16 1, 0, PLL_CTRL_EDDS_CON0
|
||||||
|
sc_write16 1, 1, PLL_CTRL_EPLL_CON0
|
||||||
|
sc_usleep 1
|
||||||
|
|
||||||
|
sc_write16 0x4000, 0x4000, PLL_CTRL_CLK_CONDB
|
||||||
|
sc_usleep 1
|
||||||
|
|
||||||
|
sc_write32 0x8048, 0, PLL_CTRL_CLK_CONDC
|
||||||
|
/* Run the SPI clock at 104 MHz */
|
||||||
|
sc_write32 0xd002, 0, PLL_CTRL_CLK_CONDH
|
||||||
|
sc_write32 0xb6a0, 0, PLL_CTRL_CLK_CONDC
|
||||||
|
sc_end
|
|
@ -8,6 +8,10 @@ disable_interrupts:
|
||||||
orr r0, r0, r1
|
orr r0, r0, r1
|
||||||
msr cpsr_cxsf, r0
|
msr cpsr_cxsf, r0
|
||||||
|
|
||||||
|
relocate_stack:
|
||||||
|
ldr r0, =0x7000bffc // stack_start
|
||||||
|
mov sp, r0
|
||||||
|
|
||||||
print_welcome_banner:
|
print_welcome_banner:
|
||||||
adr r0, welcome_banner
|
adr r0, welcome_banner
|
||||||
bl uart_puts
|
bl uart_puts
|
||||||
|
@ -25,6 +29,7 @@ load_program:
|
||||||
# r0 contains the current offset to write to.
|
# r0 contains the current offset to write to.
|
||||||
# Load bytes from the serial port into RAM.
|
# Load bytes from the serial port into RAM.
|
||||||
mov r0, #0x70000000
|
mov r0, #0x70000000
|
||||||
|
orr r0, r0, #0x6000
|
||||||
mvn r2, #0
|
mvn r2, #0
|
||||||
ldr r3, =0xfff03639
|
ldr r3, =0xfff03639
|
||||||
blx r3
|
blx r3
|
||||||
|
@ -33,6 +38,7 @@ jump_to_new_program:
|
||||||
adr r0, launch_message
|
adr r0, launch_message
|
||||||
bl uart_puts
|
bl uart_puts
|
||||||
mov r0, #0x70000000
|
mov r0, #0x70000000
|
||||||
|
orr r0, r0, #0x6000
|
||||||
mov pc, r0
|
mov pc, r0
|
||||||
|
|
||||||
.align 4
|
.align 4
|
||||||
|
|
39
utils.c
39
utils.c
|
@ -1,5 +1,6 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "serial.h"
|
#include "serial.h"
|
||||||
|
#include "printf.h"
|
||||||
|
|
||||||
static inline int _isprint(char c)
|
static inline int _isprint(char c)
|
||||||
{
|
{
|
||||||
|
@ -62,9 +63,41 @@ int serial_print_hex(const void *block, int count)
|
||||||
return serial_print_hex_offset(block, count, 0);
|
return serial_print_hex_offset(block, count, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern uint32_t __udiv64(uint32_t a, uint32_t b, uint32_t c);
|
uint32_t __div64_32(uint64_t *n, uint32_t base)
|
||||||
uint32_t _udiv64(uint64_t n, uint32_t d)
|
|
||||||
{
|
{
|
||||||
return __udiv64(n >> 32, n, d);
|
uint64_t rem = *n;
|
||||||
|
uint64_t b = base;
|
||||||
|
uint64_t res, d = 1;
|
||||||
|
uint32_t high = rem >> 32;
|
||||||
|
|
||||||
|
/* Reduce the thing a bit first */
|
||||||
|
res = 0;
|
||||||
|
if (high >= base) {
|
||||||
|
high /= base;
|
||||||
|
res = (uint64_t) high << 32;
|
||||||
|
rem -= (uint64_t) (high*base) << 32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
while ((int64_t)b > 0 && b < rem) {
|
||||||
|
b = b+b;
|
||||||
|
d = d+d;
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (rem >= b) {
|
||||||
|
rem -= b;
|
||||||
|
res += d;
|
||||||
|
}
|
||||||
|
b >>= 1;
|
||||||
|
d >>= 1;
|
||||||
|
} while (d);
|
||||||
|
|
||||||
|
*n = res;
|
||||||
|
return rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __div0 (void)
|
||||||
|
{
|
||||||
|
printf("Division by 0. Hanging.\n");
|
||||||
|
while(1);
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue