diff --git a/Makefile b/Makefile index d43f0b3..49e2cfd 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,7 @@ CFLAGS += $(CFLAGS_all) CPPFLAGS := -DBOARD_$(BOARD) -DJZ_VERSION=$(JZ_VERSION) LDFLAGS := -nostdlib -EL -ifneq ($(findstring $(JZ_VERSION),JZ4740 JZ4750),) +ifneq ($(findstring $(JZ_VERSION),JZ4740 JZ4750 JZ4725 JZ4755),) LDFLAGS += -T ldscripts/target-jz4740.ld endif @@ -38,7 +38,7 @@ endif OUTDIR := output/$(CONFIG) -OBJS := utils.o mmc.o fat.o head.o uimage.o +OBJS := utils.o mmc.o fat.o uimage.o ifdef GC_FUNCTIONS CFLAGS += -ffunction-sections @@ -82,7 +82,10 @@ OBJFILES := $(addprefix $(OUTDIR)/,$(OBJS)) all: $(BINFILES) $(ELFFILES): $(OUTDIR)/ubiboot-%.elf: \ - $(OUTDIR)/main_%.o $(OUTDIR)/board-$(BOARD)_%.o $(OBJFILES) + $(OUTDIR)/main_%.o \ + $(OUTDIR)/board-$(BOARD)_%.o \ + $(OUTDIR)/head_%.o \ + $(OBJFILES) @mkdir -p $(@D) $(SUM) " LD $@" $(CMD)$(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@ @@ -104,6 +107,13 @@ $(OUTDIR)/%.o: src/%.S CFLAGS_FOR_VARIANT=$(CFLAGS) -DVARIANT="\"$(1)\"" $(CFLAGS_$(1)) +$(OUTDIR)/head_%.o: src/head.S + @mkdir -p $(@D) + $(SUM) " CC $@" + $(CMD)$(CC) $(CFLAGS) $(CPPFLAGS) \ + $(call CFLAGS_FOR_VARIANT,$(@:$(OUTDIR)/head_%.o=%)) \ + -c $< -o $@ + $(OUTDIR)/board-$(BOARD)_%.o: src/board-$(BOARD).c @mkdir -p $(@D) $(SUM) " CC $@" diff --git a/config-rzx27.mk b/config-rzx27.mk new file mode 100644 index 0000000..9186e87 --- /dev/null +++ b/config-rzx27.mk @@ -0,0 +1,18 @@ +# Ritmix RZX-27 handheld +# - Ingenic JZ4725b +# - 32Mb SDRAM +# - 4Gb SD-card as main storage (might have NAND instead) +# - 320x240 smart LCD (UC8230 based, might have another screens) +GC_FUNCTIONS = True +USE_SERIAL = True +#BKLIGHT_ON = True +#USE_NAND = False +#USE_UBI = False + +BOARD := rzx27 + +VARIANTS := mmc +JZ_VERSION = 4725 + +CFLAGS_all := -mips32 -DTRY_ORIGINAL_FIRMWARE +CFLAGS_mmc := -DHAVE_MBR diff --git a/config-rzx50.mk b/config-rzx50.mk new file mode 100644 index 0000000..debda32 --- /dev/null +++ b/config-rzx50.mk @@ -0,0 +1,19 @@ +# Ritmix RZX-50 handheld +# - Ingenic JZ4755 +# - 64Mb SDRAM +# - 4Gb SD-card as main storage +# - 480х272 LCD +# - have 2 variants, with or without analog joystick +GC_FUNCTIONS = True +USE_SERIAL = True +#BKLIGHT_ON = True +#USE_NAND = True +#USE_UBI = True + +BOARD := rzx50 + +VARIANTS := mmc +JZ_VERSION = 4755 + +CFLAGS_all := -mips32 -DTRY_ORIGINAL_FIRMWARE +CFLAGS_mmc := -DHAVE_MBR diff --git a/src/board-rzx27.c b/src/board-rzx27.c new file mode 100644 index 0000000..80d58b0 --- /dev/null +++ b/src/board-rzx27.c @@ -0,0 +1,299 @@ +/* + * board.c + * + * Board init routines. + * + * Copyright (C) 2006 Ingenic Semiconductor Inc. + * Maintainer Siarhei Volkau + * + */ + +#include + +#include "config.h" + +#include "board.h" +#include "serial.h" +#include "utils.h" + +#include "jz.h" +#include "jz4740-cpm.h" +#include "jz4740-emc.h" +#include "jz4740-gpio.h" +#include "mmc.h" + +#define CDIV 1 +#define HDIV 3 +#define PDIV 3 +#define MDIV 3 +#define LDIV 3 + +/* PLL output clock = EXTAL * NF / (NR * NO) + * + * NF = FD + 2, NR = RD + 2 + * NO = 1 (if OD = 0), NO = 2 (if OD = 1 or 2), NO = 4 (if OD = 3) + */ +static void pll_init(void) +{ + register unsigned int cfcr, plcr1, pllout2; + static const uint8_t n2FR[33] = { + 0, 0, 1, 2, 3, 0, 4, 0, 5, 0, 0, 0, 6, 0, 0, 0, + 7, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, + 9 + }; + + cfcr = CPM_CPCCR_CLKOEN | + CPM_CPCCR_PCS | + ((unsigned int) n2FR[CDIV] << CPM_CPCCR_CDIV_BIT) | + ((unsigned int) n2FR[HDIV] << CPM_CPCCR_HDIV_BIT) | + ((unsigned int) n2FR[PDIV] << CPM_CPCCR_PDIV_BIT) | + ((unsigned int) n2FR[MDIV] << CPM_CPCCR_MDIV_BIT) | + ((unsigned int) n2FR[LDIV] << CPM_CPCCR_LDIV_BIT); + + pllout2 = (cfcr & CPM_CPCCR_PCS) ? CFG_CPU_SPEED : (CFG_CPU_SPEED / 2); + + /* Init USB Host clock, pllout2 must be n*48MHz */ + REG_CPM_UHCCDR = pllout2 / 48000000 - 1; + +#define NF (CFG_CPU_SPEED * 2 / CFG_EXTAL) + plcr1 = ((NF - 2) << CPM_CPPCR_PLLM_BIT) | /* FD */ + (0 << CPM_CPPCR_PLLN_BIT) | /* RD=0, NR=2 */ + (0 << CPM_CPPCR_PLLOD_BIT) | /* OD=0, NO=1 */ + (0x20 << CPM_CPPCR_PLLST_BIT) | /* PLL stable time */ + CPM_CPPCR_PLLEN; /* enable PLL */ + + /* init PLL */ + REG_CPM_CPCCR = cfcr; + REG_CPM_CPPCR = plcr1; + + __cpm_enable_pll_change(); + while (!__cpm_pll_is_on()); +} + +/* + * Copied from RS90 as is. However, the DRAM chip + * is ETRON EM63A165TS-6G and might have differences. + */ +#define SDRAM_CASL 3 /* CAS latency: 2 or 3 */ +#define SDRAM_TRAS 42 /* RAS# Active Time (ns) */ +#define SDRAM_RCD 18 /* RAS# to CAS# Delay (ns) */ +#define SDRAM_TPC 18 /* RAS# Precharge Time (ns) */ +#define SDRAM_TREF 15625 /* Refresh period (ns) */ +#define SDRAM_TRWL 7 /* Write Latency Time (ns) */ +#define SDRAM_BW16 1 +#define SDRAM_BANK40 0 +#define SDRAM_BANK4 1 +#define SDRAM_ROW0 11 +#define SDRAM_ROW 13 +#define SDRAM_COL0 9 +#define SDRAM_COL 9 + +static void sdram_init(void) +{ + unsigned int dmcr0, dmcr, sdmode, tmp; + + static const unsigned int cas_latency_sdmr[2] = { + EMC_SDMR_CAS_2, + EMC_SDMR_CAS_3, + }; + + static const unsigned int cas_latency_dmcr[2] = { + 1 << EMC_DMCR_TCL_BIT, /* CAS latency is 2 */ + 2 << EMC_DMCR_TCL_BIT /* CAS latency is 3 */ + }; + + REG_EMC_BCR = 0; /* Disable bus release */ + REG_EMC_RTCSR = 0; /* Disable clock for counting */ + + /* Fault DMCR value for mode register setting*/ + dmcr0 = ((SDRAM_ROW0-11)< 11) tmp = 11; + dmcr |= ((tmp-4) << EMC_DMCR_TRAS_BIT); + tmp = SDRAM_RCD/NS; + if (tmp > 3) tmp = 3; + dmcr |= (tmp << EMC_DMCR_RCD_BIT); + tmp = SDRAM_TPC/NS; + if (tmp > 7) tmp = 7; + dmcr |= (tmp << EMC_DMCR_TPC_BIT); + tmp = SDRAM_TRWL/NS; + if (tmp > 3) tmp = 3; + dmcr |= (tmp << EMC_DMCR_TRWL_BIT); + tmp = (SDRAM_TRAS + SDRAM_TPC)/NS; + if (tmp > 14) tmp = 14; + dmcr |= (((tmp + 1) >> 1) << EMC_DMCR_TRC_BIT); + + /* SDRAM mode value */ + sdmode = EMC_SDMR_BT_SEQ | + EMC_SDMR_OM_NORMAL | + EMC_SDMR_BL_4 | + cas_latency_sdmr[((SDRAM_CASL == 3) ? 1 : 0)]; + + /* Stage 1. Precharge all banks by writing SDMR with DMCR.MRSET=0 */ + REG_EMC_DMCR = dmcr; + REG8(EMC_SDMR0|sdmode) = 0; + + /* Wait for precharge, > 200us */ + udelay(1000); + + /* Stage 2. Enable auto-refresh */ + REG_EMC_DMCR = dmcr | EMC_DMCR_RFSH; + + tmp = SDRAM_TREF/NS; + tmp = tmp/64 + 1; + if (tmp > 0xff) tmp = 0xff; + REG_EMC_RTCOR = tmp; + REG_EMC_RTCNT = 0; + REG_EMC_RTCSR = EMC_RTCSR_CKS_64; /* Divisor is 64, CKO/64 */ + + /* Wait for number of auto-refresh cycles */ + udelay(1000); + + /* Stage 3. Mode Register Set */ + REG_EMC_DMCR = dmcr0 | EMC_DMCR_RFSH | EMC_DMCR_MRSET; + REG8(EMC_SDMR0|sdmode) = 0; + + /* Set back to basic DMCR value */ + REG_EMC_DMCR = dmcr | EMC_DMCR_RFSH | EMC_DMCR_MRSET; + + /* everything is ok now */ +} + +int alt_key_pressed(void) +{ + return 0; /* TODO */ +} + +int alt2_key_pressed(void) +{ + return 0; /* TODO */ +} + +int alt3_key_pressed(void) +{ + return 0; /* TODO */ +} + +#ifdef BKLIGHT_ON +void light(int set) +{ + if (set) + __gpio_set_pin(GPIOC, 15); + else + __gpio_clear_pin(GPIOC, 15); +} +#endif + +unsigned int get_memory_size(void) +{ + return 1 << (SDRAM_ROW + SDRAM_COL + (2 - SDRAM_BW16) + + (2 - SDRAM_BANK4) + 1); +} + +void board_init(void) +{ +#ifdef USE_NAND + __gpio_as_func_mask(GPIOC, 0x36300300, 0); + __gpio_as_input(GPIOC, 27); + __gpio_disable_pull(GPIOC, 27); +#else + /* MSC0 pins */ + __gpio_as_func_mask(GPIOC, 0x30400300, 1); + __gpio_as_func_mask(GPIOC, 0x08000000, 0); +#endif + + /* SDRAM pins */ + __gpio_as_func_mask(0, 0xffff, 0); + __gpio_as_func_mask(1, 0x033fffff, 0); + + /* MSC1 pins */ + __gpio_as_func_mask(GPIOD, 0x1c000000, 0); + +#ifdef USE_SERIAL + __gpio_as_func(2, 12, 1); /* UART_TX */ + + /* Start UART clock */ + REG_CPM_CLKGR &= ~BIT(0); + + serial_init(); +#endif + + pll_init(); + SERIAL_PUTS_ARGI("PLL running at ", __cpm_get_pllout() / 1000000, " MHz.\n"); + + sdram_init(); + SERIAL_PUTS_ARGI("SDRAM running at ", __cpm_get_mclk() / 1000000, " MHz.\n"); + SERIAL_PUTS_ARGI("SDRAM size is ", get_memory_size() / 1048576, " MiB.\n"); + +#ifdef BKLIGHT_ON + __gpio_set_pin(GPIOC, 15); + __gpio_as_output(GPIOC, 15); +#endif + + /* Ungate MSC0/1 clock */ + REG_CPM_CLKGR &= ~(BIT(6) | BIT(16)); + + /* Set divider for the MSC0/1 clock */ + __cpm_set_mscdiv((__cpm_get_pllout2() / 24000000) - 1); +} + +#ifdef USE_NAND +void nand_wait_ready(void) +{ + unsigned int timeout = 10000; + + while (__gpio_get_pin(GPIOC, 27) && timeout--); + while (!__gpio_get_pin(GPIOC, 27)); +} + +void nand_init(void) +{ + REG32(EMC_SMCR1) = (EMC_TAS << EMC_SMCR_TAS_BIT) | + (EMC_TAH << EMC_SMCR_TAH_BIT) | + (EMC_TBP << EMC_SMCR_TBP_BIT) | + (EMC_TAW << EMC_SMCR_TAW_BIT) | + (EMC_STRV << EMC_SMCR_STRV_BIT); +} +#endif + +void original_firmware_load(void) +{ + // internal MSC0 shall be initialized first + // original firmware is at 256kiB offset on SD card. + // shall be loaded at 0x00800000 offset in RAM + + const uint32_t load_addr = 0x00800000; + // load 1MiB bytes into RAM from 512 blocks (256kiB) offset on SD card. + if (!mmc_block_read(0, (void *) (KSEG1 + load_addr), 512, 2048)) { + + SERIAL_PUTS("Trying original RZX-27 firmware from internal SD.\n"); + + // TODO check that loaded data not a crap + // reset the LCD controller for proper reintialization + __gpio_clear_pin(GPIOD, 21); + udelay(1000); + __gpio_set_pin(GPIOD, 21); + + // jump into firmware + void (*entry)(void) = (void (*)(void))(KSEG1 + load_addr); + entry(); + while (1); + } +} diff --git a/src/board-rzx50.c b/src/board-rzx50.c new file mode 100644 index 0000000..6835c70 --- /dev/null +++ b/src/board-rzx50.c @@ -0,0 +1,363 @@ +/* + * board.c + * + * Board init routines. + * + * Copyright (C) 2006 Ingenic Semiconductor Inc. + * Maintainer Siarhei Volkau + * + */ + +#include + +#include "config.h" + +/* HACK actual freq is 24M but for peripheral it divised by 2 in pll_init + * this allows to use 12M for rest of the source code e.g. serial.c + */ +#undef CFG_EXTAL +#define CFG_EXTAL 24000000 + +#include "board.h" +#include "serial.h" +#include "utils.h" + +#include "jz.h" +#include "jz4740-cpm.h" +#include "jz4740-emc.h" +#include "jz4740-gpio.h" +#include "mmc.h" + +#define CDIV 1 +#define H0DIV 3 +#define PDIV 3 +#define MDIV 3 +#define H1DIV 2 + +#define NS (1000000000 / (CFG_CPU_SPEED * CDIV / MDIV)) + +/* PLL output clock = EXTAL * NF / (NR * NO) + * + * NF = FD + 2, NR = RD + 2 + * NO = 1 (if OD = 0), NO = 2 (if OD = 1 or 2), NO = 4 (if OD = 3) + */ +static void pll_init(void) +{ + register unsigned int cfcr, plcr1; + static const uint8_t n2FR[9] = { + 0, 0, 1, 2, 3, 0, 4, 0, 5 + }; + + cfcr = CPM_CPCCR_CLKOEN | CPM_CPCCR_PCS | + ((unsigned int) n2FR[CDIV] << CPM_CPCCR_CDIV_BIT) | + ((unsigned int) n2FR[H0DIV] << CPM_CPCCR_HDIV_BIT) | + ((unsigned int) n2FR[PDIV] << CPM_CPCCR_PDIV_BIT) | + ((unsigned int) n2FR[MDIV] << CPM_CPCCR_MDIV_BIT) | + ((unsigned int) n2FR[H1DIV] << CPM_CPCCR_LDIV_BIT); + +#define NF (CFG_CPU_SPEED * 2 / CFG_EXTAL) + plcr1 = ((NF - 2) << CPM_CPPCR_PLLM_BIT) | /* FD */ + (0 << CPM_CPPCR_PLLN_BIT) | /* RD=0, NR=2 */ + (0 << CPM_CPPCR_PLLOD_BIT) | /* OD=0, NO=1 */ + (0x20 << CPM_CPPCR_PLLST_BIT) | /* PLL stable time */ + CPM_CPPCR_PLLEN; /* enable PLL */ + + /* init PLL */ + REG_CPM_CPCCR = cfcr; + REG_CPM_CPPCR = plcr1; + + __cpm_enable_pll_change(); + while (!__cpm_pll_is_on()); +} + +/* + * Those settings are matched settings from + * original U-Boot. + */ +#define SDRAM_CASL 2 /* CAS latency: 2 or 3 */ +#define SDRAM_TRAS 42 /* RAS# Active Time (ns) */ +#define SDRAM_RCD 18 /* RAS# to CAS# Delay (ns) */ +#define SDRAM_TPC 18 /* RAS# Precharge Time (ns) */ +#define SDRAM_TREF 15625 /* Refresh period (ns) */ +#define SDRAM_TRWL 7 /* Write Latency Time (ns) */ +#define SDRAM_BW16 0 +#define SDRAM_BANK40 0 +#define SDRAM_BANK4 1 +#define SDRAM_ROW0 11 +#define SDRAM_ROW 13 +#define SDRAM_COL0 9 +#define SDRAM_COL 9 +#define NR_DRAM_BANKS 1 +//#define MOBILE_SDRAM + +/* JZ4750/4755 specific */ +#define EMC_MEM_PHY_BASE 0x20000000 +#define EMC_MEM_PHY_BASE_SHIFT 24 + +static inline unsigned int get_ram_size_per_bank(void) +{ + u32 dmcr; + u32 rows, cols, dw, banks; + ulong size; + + dmcr = REG_EMC_DMCR; + rows = 11 + ((dmcr & EMC_DMCR_RA_MASK) >> EMC_DMCR_RA_BIT); + cols = 8 + ((dmcr & EMC_DMCR_CA_MASK) >> EMC_DMCR_CA_BIT); + dw = (dmcr & EMC_DMCR_BW) ? 2 : 4; + banks = (dmcr & EMC_DMCR_BA) ? 4 : 2; + + size = (1 << (rows + cols)) * dw * banks; + + return size; +} + +void sdram_init(void) +{ + unsigned int dmcr, sdmode, tmp; + +#ifdef MOBILE_SDRAM + unsigned int sdemode; /*SDRAM Extended Mode*/ +#endif + unsigned int cas_latency_sdmr[2] = { + EMC_SDMR_CAS_2, + EMC_SDMR_CAS_3, + }; + + unsigned int cas_latency_dmcr[2] = { + 1 << EMC_DMCR_TCL_BIT, /* CAS latency is 2 */ + 2 << EMC_DMCR_TCL_BIT /* CAS latency is 3 */ + }; + + REG_EMC_BCR = 0; /* Disable bus release */ + REG_EMC_RTCSR = 0; /* Disable clock for counting */ + + /* Basic DMCR value */ + dmcr = ((SDRAM_ROW-11)< 11) tmp = 11; + dmcr |= ((tmp-4) << EMC_DMCR_TRAS_BIT); + tmp = SDRAM_RCD/NS; + if (tmp > 3) tmp = 3; + dmcr |= (tmp << EMC_DMCR_RCD_BIT); + tmp = SDRAM_TPC/NS; + if (tmp > 7) tmp = 7; + dmcr |= (tmp << EMC_DMCR_TPC_BIT); + tmp = SDRAM_TRWL/NS; + if (tmp > 3) tmp = 3; + dmcr |= (tmp << EMC_DMCR_TRWL_BIT); + tmp = (SDRAM_TRAS + SDRAM_TPC)/NS; + if (tmp > 14) tmp = 14; + dmcr |= (((tmp + 1) >> 1) << EMC_DMCR_TRC_BIT); + + /* SDRAM mode value */ + sdmode = EMC_SDMR_BT_SEQ | + EMC_SDMR_OM_NORMAL | + EMC_SDMR_BL_4 | + cas_latency_sdmr[((SDRAM_CASL == 3) ? 1 : 0)]; + + /* Stage 1. Precharge all banks by writing SDMR with DMCR.MRSET=0 */ + REG_EMC_DMCR = dmcr; + REG8(EMC_SDMR0|sdmode) = 0; + + /* Precharge Bank1 SDRAM */ +#if NR_DRAM_BANKS == 2 + REG_EMC_DMCR = dmcr | EMC_DMCR_MBSEL; + REG8(EMC_SDMR0|sdmode) = 0; +#endif + +#ifdef MOBILE_SDRAM + /* Mobile SDRAM Extended Mode Register */ + sdemode = EMC_SDMR_SET_BA1 | EMC_SDMR_DS_HALF | EMC_SDMR_PRSR_ALL; +#endif + + /* Wait for precharge, > 200us */ + udelay(1000); + + /* Stage 2. Enable auto-refresh */ + REG_EMC_DMCR = dmcr | EMC_DMCR_RFSH; + + tmp = SDRAM_TREF/NS; + tmp = tmp/64 + 1; + if (tmp > 0xff) tmp = 0xff; + REG_EMC_RTCOR = tmp; + REG_EMC_RTCNT = 0; + REG_EMC_RTCSR = EMC_RTCSR_CKS_64; /* Divisor is 64, CKO/64 */ + + /* Wait for number of auto-refresh cycles */ + udelay(1000); + + /* Stage 3. Mode Register Set */ + REG_EMC_DMCR = dmcr | EMC_DMCR_RFSH | EMC_DMCR_MRSET; + REG8(EMC_SDMR0|sdmode) = 0; + + +#ifdef MOBILE_SDRAM + REG8(EMC_SDMR0|sdemode) = 0; /* Set Mobile SDRAM Extended Mode Register */ +#endif + +#if NR_DRAM_BANKS == 2 + REG_EMC_DMCR = dmcr | EMC_DMCR_RFSH | EMC_DMCR_MRSET | EMC_DMCR_MBSEL; + REG8(EMC_SDMR0|sdmode) = 0; /* Set Bank1 SDRAM Register */ + + +#ifdef MOBILE_SDRAM + REG8(EMC_SDMR0|sdemode) = 0; /* Set Mobile SDRAM Extended Mode Register */ +#endif + +#endif /*NR_DRAM_BANKS == 2*/ + + /* Set back to basic DMCR value */ + REG_EMC_DMCR = dmcr | EMC_DMCR_RFSH | EMC_DMCR_MRSET; + + /* bank_size: 32M 64M 128M ... */ + unsigned int bank_size = get_ram_size_per_bank(); + unsigned int mem_base0, mem_base1, mem_mask; + + mem_base0 = EMC_MEM_PHY_BASE >> EMC_MEM_PHY_BASE_SHIFT; + mem_base1 = ((EMC_MEM_PHY_BASE + bank_size) >> EMC_MEM_PHY_BASE_SHIFT); + mem_mask = EMC_DMAR_MASK_MASK & + (~(((bank_size) >> EMC_MEM_PHY_BASE_SHIFT)-1) & EMC_DMAR_MASK_MASK); + + REG_EMC_DMAR0 = (mem_base0 << EMC_DMAR_BASE_BIT) | mem_mask; + REG_EMC_DMAR1 = (mem_base1 << EMC_DMAR_BASE_BIT) | mem_mask; + + /* everything is ok now */ +} + +int alt_key_pressed(void) +{ + return 0; /* TODO */ +} + +int alt2_key_pressed(void) +{ + return 0; /* TODO */ +} + +int alt3_key_pressed(void) +{ + return 0; /* TODO */ +} + +#ifdef BKLIGHT_ON +void light(int set) +{ + if (set) + __gpio_clear_pin(GPIOE, 22); + else + __gpio_set_pin(GPIOE, 22); +} +#endif + +unsigned int get_memory_size(void) +{ + return 1 << (SDRAM_ROW + SDRAM_COL + (2 - SDRAM_BW16) + + (2 - SDRAM_BANK4) + NR_DRAM_BANKS); +} + +void board_init(void) +{ + /* SDRAM pins */ + __gpio_as_func_mask(GPIOA, 0xffffffff, 0); + __gpio_as_func_mask(GPIOB, 0x03ff7fff, 0); + + /* MSC0 pins */ + __gpio_as_func(GPIOB, 15, 2); + __gpio_as_func(GPIOC, 27, 0); + __gpio_as_func(GPIOC, 16, 2); + __gpio_as_func_mask(GPIOC, 0x30020000, 1); + + /* MSC1 pins */ + __gpio_as_func_mask(GPIOB, 0xfc000000, 1); + +#ifdef USE_SERIAL + __gpio_as_func(GPIOE, 25, 1); /* UART_TX */ + + /* Start UART clock */ + REG_CPM_CLKGR &= ~BIT(14); + + serial_init(); +#endif + pll_init(); + SERIAL_PUTS_ARGI("PLL running at ", __cpm_get_pllout() / 1000000, " MHz.\n"); + + sdram_init(); + SERIAL_PUTS_ARGI("SDRAM running at ", __cpm_get_mclk() / 1000000, " MHz.\n"); + SERIAL_PUTS_ARGI("SDRAM size is ", get_memory_size() / 1048576, " MiB.\n"); + +#if 1 +#ifdef BKLIGHT_ON + __gpio_set_pin(GPIOE, 22); + __gpio_as_output(GPIOE, 22); +#endif +#endif + /* Ungate MSC0/1 clock */ + REG_CPM_CLKGR &= ~(BIT(6) | BIT(16)); + + /* Set divider for the MSC0/1 clock */ + __cpm_set_mscdiv((__cpm_get_pllout2() / 24000000) - 1); +} + +#ifdef USE_NAND +void nand_wait_ready(void) +{ + unsigned int timeout = 10000; + + while (__gpio_get_pin(GPIOC, 27) && timeout--); + while (!__gpio_get_pin(GPIOC, 27)); +} + +void nand_init(void) +{ + REG32(EMC_SMCR1) = (EMC_TAS << EMC_SMCR_TAS_BIT) | + (EMC_TAH << EMC_SMCR_TAH_BIT) | + (EMC_TBP << EMC_SMCR_TBP_BIT) | + (EMC_TAW << EMC_SMCR_TAW_BIT) | + (EMC_STRV << EMC_SMCR_STRV_BIT); +} +#endif + +#define USB_BASE 0xB3040000 + +#define REG_USB_FADDR REG8(USB_BASE + 0x00) /* Function Address 8-bit */ +#define REG_USB_POWER REG8(USB_BASE + 0x01) /* Power Managemetn 8-bit */ + +void original_firmware_load(void) +{ + // internal MSC0 shall be initialized first + // original u-boot is at 16kiB offset on SD card. + // shall be loaded at 0x00100000 offset in RAM + // loading up to 1MiB is sufficient + + const uint32_t load_addr = 0x00100000; + const uint32_t entry_offset = 0x200; + + SERIAL_PUTS("Trying original RZX-50 firmware from internal SD.\n"); + + if (!mmc_block_read(0, (void *) (KSEG1 + load_addr), 32, 2048-32)) { + uint32_t cmd_1st = *(uint32_t*)(KSEG1 + load_addr + entry_offset); + + // first uboot command is always `bal 1f` => 0x04110002 in hex + if (cmd_1st != 0x04110002) { + SERIAL_PUTS("Unexpected content, booting might fail.\n"); + } + + /* reset USB to defaults, otherwise it won't work in original kernel. + * starting UBIBoot over USB case */ + REG_USB_POWER = 0x20; + REG_USB_FADDR = 0x80; + + void (*entry)(void) = (void (*)(void))(KSEG1 + load_addr + entry_offset); + entry(); + while (1); + } + SERIAL_PUTS("Can't read firmware from SD.\n"); +} diff --git a/src/board.h b/src/board.h index 54970a1..daed0dc 100644 --- a/src/board.h +++ b/src/board.h @@ -12,5 +12,9 @@ unsigned int get_memory_size(void); void nand_init(void); void nand_wait_ready(void); +#ifdef TRY_ORIGINAL_FIRMWARE +void original_firmware_load(void); +#endif + #endif diff --git a/src/config-a320.h b/src/config-a320.h index a280833..1f4e04b 100644 --- a/src/config-a320.h +++ b/src/config-a320.h @@ -24,6 +24,7 @@ #define ECC_BLOCK 512 #define ECC_POS 6 #define PAR_SIZE 9 +#define UBIBOOT_DESTINATION DESTINATION_NAND /* UBI parameters */ #define UBI_MTD_EB_START 5 @@ -34,4 +35,5 @@ #define UBI_ROOTFS_VOLUME "rootfs" /* MMC parameters */ -#define MMC_ID 0 +#define MMC_IDS { 0 } +#define MMC_BLKIDS { 0 } diff --git a/src/config-gcw0.h b/src/config-gcw0.h index c2a74da..c282813 100644 --- a/src/config-gcw0.h +++ b/src/config-gcw0.h @@ -16,9 +16,12 @@ #define USES_HIGHMEM +#define UBIBOOT_DESTINATION DESTINATION_MMC + /* serial parameters */ #define LOG_UART 2 #define LOG_BAUDRATE 57600 /* MMC parameters */ -#define MMC_ID 0 +#define MMC_IDS { 0 } +#define MMC_BLKIDS { 0 } diff --git a/src/config-lepus.h b/src/config-lepus.h index af7927a..4e2d752 100644 --- a/src/config-lepus.h +++ b/src/config-lepus.h @@ -20,10 +20,12 @@ //#define USES_HIGHMEM +#define UBIBOOT_DESTINATION DESTINATION_MMC + /* serial parameters */ #define LOG_UART 1 #define LOG_BAUDRATE 57600 /* MMC parameters */ -#define MMC_ID 0 -#define MMC_ID2 2 +#define MMC_IDS { 0, 2 } /* try internal MSC0 first, MSC2 is the second */ +#define MMC_BLKIDS { 0, 1 } /* /dev/mmcblkN */ diff --git a/src/config-rs90.h b/src/config-rs90.h index 79c6814..b7902d4 100644 --- a/src/config-rs90.h +++ b/src/config-rs90.h @@ -13,8 +13,11 @@ #define LOG_UART 0 #define LOG_BAUDRATE 57600 +#define UBIBOOT_DESTINATION DESTINATION_NAND + /* MMC parameters */ -#define MMC_ID 1 +#define MMC_IDS { 1 } +#define MMC_BLKIDS { 0 } #define MMC_1BIT 1 /* NAND parameters */ diff --git a/src/config-rzx27.h b/src/config-rzx27.h new file mode 100644 index 0000000..bad063e --- /dev/null +++ b/src/config-rzx27.h @@ -0,0 +1,21 @@ +/* Board-specific config for the RZX27. */ + +#ifndef _CONFIG_H +#error Include "config.h" instead +#endif + +#define CFG_CPU_SPEED 360000000 +#define CFG_EXTAL 12000000 + +#define SYSPART_INIT "/mininit-syspart" + +/* serial parameters */ +#define LOG_UART 0 +#define LOG_BAUDRATE 57600 + +#define UBIBOOT_DESTINATION DESTINATION_MMC + +/* MMC parameters */ +#define MMC_IDS { 1, 0 } /* try external first */ +#define MMC_BLKIDS { 1, 0 } +#define MMC_1BIT 1 diff --git a/src/config-rzx50.h b/src/config-rzx50.h new file mode 100644 index 0000000..e38a85e --- /dev/null +++ b/src/config-rzx50.h @@ -0,0 +1,22 @@ +/* Board-specific config for the RZX27. */ + +#ifndef _CONFIG_H +#error Include "config.h" instead +#endif + +#define CFG_CPU_SPEED 432000000 +/* Actually its 24MHz but peripherals working on CFG_EXTAL/2 */ +/* This fixes UART speed, however its redefined to 24M in board file */ +#define CFG_EXTAL 12000000 + +#define SYSPART_INIT "/mininit-syspart" + +/* serial parameters */ +#define LOG_UART 1 +#define LOG_BAUDRATE 57600 + +#define UBIBOOT_DESTINATION DESTINATION_MMC + +/* MMC parameters */ +#define MMC_IDS { 1, 0 } /* try external first */ +#define MMC_BLKIDS { 1, 0 } /* /dev/mmcblkX to set root properly */ diff --git a/src/config.h b/src/config.h index 2f67882..4454a8c 100644 --- a/src/config.h +++ b/src/config.h @@ -1,6 +1,10 @@ #ifndef _CONFIG_H #define _CONFIG_H +/* UBIBoot destination storages */ +#define DESTINATION_NAND (1) +#define DESTINATION_MMC (2) + /* FAT parameters */ /* File names must be 8+3 characters, with spaces at unused positions. */ #define FAT_BOOTFILE_NAME "VMLINUZ BIN" @@ -24,6 +28,10 @@ #include "config-rs90.h" #elif defined(BOARD_lepus) #include "config-lepus.h" +#elif defined(BOARD_rzx27) +#include "config-rzx27.h" +#elif defined(BOARD_rzx50) +#include "config-rzx50.h" #else #error "No config for your board" #endif diff --git a/src/head.S b/src/head.S index d4f7cdd..6b9b189 100644 --- a/src/head.S +++ b/src/head.S @@ -27,11 +27,8 @@ _start: //---------------------------------------------------- #ifndef STAGE1_ONLY -#if JZ_VERSION >= 4760 - // The JZ4760 and JZ4770 won't load the program - // if the first word is not 'MSPL' - .word 0x4d53504c -#elif JZ_VERSION >= 4750 +#if UBIBOOT_DESTINATION == DESTINATION_NAND +#if JZ_VERSION == 4750 #if BUS_WIDTH == 8 .word 0x555555ff #else @@ -54,7 +51,9 @@ _start: .byte 0x00 #endif .byte 0x00 -#else /* JZ4740 */ + /* Without a NOP here it won't boot on the RS90. Go figure. */ + nop +#elif JZ_VERSION == 4740 #if BUS_WIDTH == 8 #if ROW_CYCLE == 3 addiu zero, zero, 0xffff @@ -68,11 +67,39 @@ _start: addiu zero, zero, 0x0000 #endif #endif +#else +#error "Booting from NAND doesn't supported yet for the SoC" #endif +#elif UBIBOOT_DESTINATION == DESTINATION_MMC +#if JZ_VERSION == 4725 || JZ_VERSION == 4760 || JZ_VERSION == 4770 + /* Those won't load the program + * if the first word is not 'MSPL' */ + .word 0x4d53504c +#elif JZ_VERSION == 4755 + /* It has no header (at least RZX-50 case) */ +#else +#error "Booting from MMC doesn't supported yet for the SoC" #endif +#ifdef HAVE_MBR + j _endmbr /* Jump over MBR immediately */ + nop /* delay slot */ - /* Without a NOP here it won't boot on the RS90. Go figure. */ - nop + /* 504 bytes reserved for MBR. + * overalloc a bit whether header is present */ + .word 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .word 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .word 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .word 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .word 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .word 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .word 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .word 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +_endmbr: +#endif +#else +#error "UBIBOOT_DESTINATION is not set, check your config-.h file" +#endif +#endif /* STAGE1_ONLY */ /* Disable interrupts in CP0_STATUS */ li $8, 0x00400004 diff --git a/src/jz4740-emc.h b/src/jz4740-emc.h index 3cd4449..58d15e6 100644 --- a/src/jz4740-emc.h +++ b/src/jz4740-emc.h @@ -36,8 +36,10 @@ #define EMC_RTCNT (EMC_BASE + 0x88) /* Refresh Timer Counter */ #define EMC_RTCOR (EMC_BASE + 0x8c) /* Refresh Time Constant Register */ #define EMC_DMAR0 (EMC_BASE + 0x90) /* SDRAM Bank 0 Addr Config Register */ -#if JZ_VERSION == 4750 +#if (JZ_VERSION == 4750) || (JZ_VERSION == 4755) || (JZ_VERSION == 4725) #define EMC_SDMR0 (EMC_BASE + 0x8000) /* Mode Register of SDRAM bank 0 */ +#define EMC_DMAR1 (EMC_BASE + 0x94) /* SDRAM Bank 1 Addr Config Register */ +#define EMC_BCR_BRE (1 << 1) #else #define EMC_SDMR0 (EMC_BASE + 0xa000) /* Mode Register of SDRAM bank 0 */ #endif @@ -73,6 +75,9 @@ #define REG_EMC_RTCNT REG16(EMC_RTCNT) #define REG_EMC_RTCOR REG16(EMC_RTCOR) #define REG_EMC_DMAR0 REG32(EMC_DMAR0) +#if (JZ_VERSION == 4750) || (JZ_VERSION == 4755) || (JZ_VERSION == 4725) +#define REG_EMC_DMAR1 REG32(EMC_DMAR1) +#endif /* Static Memory Control Register */ #define EMC_SMCR_STRV_BIT 24 @@ -177,6 +182,10 @@ #define EMC_DMCR_BA (1 << EMC_DMCR_BA_BIT) #define EMC_DMCR_PDM (1 << 18) #define EMC_DMCR_EPIN (1 << 17) +#if (JZ_VERSION == 4750) || (JZ_VERSION == 4755) || (JZ_VERSION == 4725) +#define EMC_DMCR_MBSEL_BIT 16 +#define EMC_DMCR_MBSEL (1 << EMC_DMCR_MBSEL_BIT) +#endif #define EMC_DMCR_TRAS_BIT 13 #define EMC_DMCR_TRAS_MASK (0x07 << EMC_DMCR_TRAS_BIT) #define EMC_DMCR_RCD_BIT 11 @@ -239,4 +248,22 @@ #define EMC_SDMR_CAS3_32BIT \ (EMC_SDMR_CAS_3 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_4) + /* Extended Mode Register of Mobile SDRAM*/ +#define EMC_SDMR_SET_BA1 (1 << 14) /*BA1*/ +#define EMC_SDMR_SET_BA0 (1 << 13) /*BA0*/ + +#define EMC_SDMR_DS_BIT 5 /* Driver strength */ +#define EMC_SDMR_DS_MASK (3 << EMC_SDMR_DS_BIT) + #define EMC_SDMR_DS_FULL (0 << EMC_SDMR_DS_BIT) /*Full*/ + #define EMC_SDMR_DS_HALF (1 << EMC_SDMR_DS_BIT) /*1/2 Strength*/ + #define EMC_SDMR_DS_QUTR (2 << EMC_SDMR_DS_BIT) /*1/4 Strength*/ + +#define EMC_SDMR_PRSR_BIT 0 /* Partial Array Self Refresh */ +#define EMC_SDMR_PRSR_MASK (7 << EMC_SDMR_PRSR_BIT) + #define EMC_SDMR_PRSR_ALL (0 << EMC_SDMR_PRSR_BIT) /*All Banks*/ + #define EMC_SDMR_PRSR_HALF_TL (1 << EMC_SDMR_PRSR_BIT) /*Half of Total Bank*/ + #define EMC_SDMR_PRSR_QUTR_TL (2 << EMC_SDMR_PRSR_BIT) /*Quarter of Total Bank*/ + #define EMC_SDMR_PRSR_HALF_B0 (5 << EMC_SDMR_PRSR_BIT) /*Half of Bank0*/ + #define EMC_SDMR_PRSR_QUTR_B0 (6 << EMC_SDMR_PRSR_BIT) /*Quarter of Bank0*/ + #endif /* __JZ4740_EMC_H__ */ diff --git a/src/main.c b/src/main.c index 7c191ea..5271a2c 100644 --- a/src/main.c +++ b/src/main.c @@ -132,6 +132,11 @@ static char *kernel_params[] = { #endif }; +static const int mmc_ids[] = MMC_IDS; +#define MMCS_COUNT (sizeof(mmc_ids) / sizeof(mmc_ids[0])) + +static const int blkids[MMCS_COUNT] = MMC_BLKIDS; + static void set_alt_param(void) { kernel_params[PARAM_KERNEL_BAK] = "kernel_bak"; @@ -170,9 +175,10 @@ typedef void (*kernel_main)(int, char**, char**, int*) __attribute__((noreturn)) void c_main(void) { void *exec_addr = NULL; - int mmc_inited, alt_kernel; + int alt_kernel; extern unsigned int _bss_start, _bss_end; unsigned int *ptr; + int mmc_inited[MMCS_COUNT] = { 0 }; /* Clear the BSS section */ for (ptr = &_bss_start; ptr < &_bss_end; ptr++) @@ -196,6 +202,7 @@ void c_main(void) } SERIAL_PUTS("UBIBoot by Paul Cercueil \n"); + #ifdef BKLIGHT_ON light(1); #endif @@ -213,33 +220,39 @@ void c_main(void) * miss and therefore cause no evictions. */ - int id = MMC_ID; - mmc_inited = !mmc_init(MMC_ID); - char *rootfs_dev = "root=/dev/mmcblk0p1"; + for (unsigned i = 0; i < MMCS_COUNT; i++) { + int ret; -#ifdef MMC_ID2 - if (!mmc_inited) { - rootfs_dev = "root=/dev/mmcblk1p1"; - id = MMC_ID2; - mmc_inited = !mmc_init(MMC_ID2); - } -#endif - - if (mmc_inited) { - if (mmc_load_kernel( - id, (void *) (KSEG1 + LD_ADDR), alt_kernel, - &exec_addr) == 1) - set_alt_param(); + mmc_inited[i] = !mmc_init(mmc_ids[i]); + if (!mmc_inited[i]) + continue; + ret = mmc_load_kernel(mmc_ids[i], (void*)(KSEG1 + LD_ADDR), + alt_kernel, &exec_addr); if (exec_addr) { #if PASS_ROOTFS_PARAMS + char *rootfs_dev = "root=/dev/mmcblk_p1"; + + rootfs_dev[16] = '0' + blkids[i]; kernel_params[PARAM_ROOTDEV] = rootfs_dev; kernel_params[PARAM_ROOTTYPE] = "rootfstype=vfat"; #endif + if (ret == 1) + set_alt_param(); + break; } } - if (!mmc_inited || !exec_addr) { +#ifdef TRY_ORIGINAL_FIRMWARE + if (!exec_addr) { + for (unsigned i = 0; i < MMCS_COUNT; i++) { + /* MMC0 is internal usually on dual-MMC devices */ + if (mmc_ids[i] == 0 && mmc_inited[i]) + original_firmware_load(); + } + } +#endif + if (!exec_addr) { SERIAL_PUTS("Unable to boot from SD." #ifdef USE_NAND " Falling back to NAND."