From da8587eaedf09e230b63b51b2dac7d1676b7f3cd Mon Sep 17 00:00:00 2001 From: jkunz Date: Tue, 20 Nov 2012 19:08:45 +0000 Subject: [PATCH] Add initial support for Olimex iMX233 based OLinuXino boards. https://www.olimex.com/Products/OLinuXino/iMX233/ Contributed by Petri Laakso. --- distrib/sets/lists/base/md.evbarm | 3 +- sys/arch/evbarm/conf/IMX23_OLINUXINO | 57 ++ sys/arch/evbarm/conf/files.imx23_olinuxino | 10 + sys/arch/evbarm/conf/mk.imx23_olinuxino | 7 + sys/arch/evbarm/conf/std.imx23_olinuxino | 21 + .../imx23_olinuxino/imx23_olinuxino_machdep.c | 679 ++++++++++++++++++ .../imx23_olinuxino/imx23_olinuxino_start.S | 185 +++++ sys/arch/evbarm/stand/Makefile | 3 +- sys/arch/evbarm/stand/bootimx23/Makefile | 52 ++ sys/arch/evbarm/stand/bootimx23/boot_prep.c | 68 ++ sys/arch/evbarm/stand/bootimx23/bootimx23.bd | 31 + sys/arch/evbarm/stand/bootimx23/clock_prep.c | 255 +++++++ sys/arch/evbarm/stand/bootimx23/common.c | 69 ++ sys/arch/evbarm/stand/bootimx23/common.h | 52 ++ sys/arch/evbarm/stand/bootimx23/emi_prep.c | 151 ++++ .../evbarm/stand/bootimx23/pinctrl_prep.c | 485 +++++++++++++ sys/arch/evbarm/stand/bootimx23/power_prep.c | 579 +++++++++++++++ 17 files changed, 2705 insertions(+), 2 deletions(-) create mode 100644 sys/arch/evbarm/conf/IMX23_OLINUXINO create mode 100644 sys/arch/evbarm/conf/files.imx23_olinuxino create mode 100644 sys/arch/evbarm/conf/mk.imx23_olinuxino create mode 100644 sys/arch/evbarm/conf/std.imx23_olinuxino create mode 100644 sys/arch/evbarm/imx23_olinuxino/imx23_olinuxino_machdep.c create mode 100644 sys/arch/evbarm/imx23_olinuxino/imx23_olinuxino_start.S create mode 100644 sys/arch/evbarm/stand/bootimx23/Makefile create mode 100644 sys/arch/evbarm/stand/bootimx23/boot_prep.c create mode 100644 sys/arch/evbarm/stand/bootimx23/bootimx23.bd create mode 100644 sys/arch/evbarm/stand/bootimx23/clock_prep.c create mode 100644 sys/arch/evbarm/stand/bootimx23/common.c create mode 100644 sys/arch/evbarm/stand/bootimx23/common.h create mode 100644 sys/arch/evbarm/stand/bootimx23/emi_prep.c create mode 100644 sys/arch/evbarm/stand/bootimx23/pinctrl_prep.c create mode 100644 sys/arch/evbarm/stand/bootimx23/power_prep.c diff --git a/distrib/sets/lists/base/md.evbarm b/distrib/sets/lists/base/md.evbarm index b994d2d1a2b2..285c4ad8bc74 100644 --- a/distrib/sets/lists/base/md.evbarm +++ b/distrib/sets/lists/base/md.evbarm @@ -1,4 +1,4 @@ -# $NetBSD: md.evbarm,v 1.11 2012/11/15 19:49:11 jkunz Exp $ +# $NetBSD: md.evbarm,v 1.12 2012/11/20 19:09:47 jkunz Exp $ ./usr/mdec/gzboot_ADI_BRH_0x00140000.bin base-sysutil-bin ./usr/mdec/gzboot_GEMINI_0x01600000.bin base-sysutil-bin ./usr/mdec/gzboot_IQ80310_0x00080000.bin base-sysutil-bin @@ -8,6 +8,7 @@ ./usr/mdec/gzboot_SMDK2800_0x00100000.bin base-sysutil-bin ./usr/mdec/gzboot_TS7200_0x60660000.bin base-sysutil-bin ./usr/mdec/bootmini2440 base-sysutil-bin +./usr/mdec/bootimx23 base-sysutil-bin ./usr/sbin/elftosb base-sysutil-bin ./usr/sbin/sbtool base-sysutil-bin ./usr/sbin/sbkeygen base-sysutil-bin diff --git a/sys/arch/evbarm/conf/IMX23_OLINUXINO b/sys/arch/evbarm/conf/IMX23_OLINUXINO new file mode 100644 index 000000000000..272bfe5d1953 --- /dev/null +++ b/sys/arch/evbarm/conf/IMX23_OLINUXINO @@ -0,0 +1,57 @@ +# $Id: IMX23_OLINUXINO,v 1.1 2012/11/20 19:08:45 jkunz Exp $ +# +# IMX23_OLINUXINO -- Olimex i.MX23 OLinuXino kernel configuration file. +# + +include "arch/evbarm/conf/std.imx23_olinuxino" + +maxusers 8 + +config netbsd root on ? type ? + +# The main bus device +mainbus0 at root + +# The boot CPU +cpu0 at mainbus? + +# APBH bus +apbh0 at mainbus? base 0x80000000 size 0x00040000 + +# APBH DMA +#apbdma0 at apbh? addr 0x80004000 size 0x2000 irq -1 + +# Interrupt controller +icoll0 at apbh? addr 0x80000000 size 0x2000 irq -1 + +# Synchronous serial port for SD/MMC +#ssp0 at apbh? addr 0x80010000 size 0x2000 irq 15 +#sdmmc* at ssp? +#ld* at sdmmc? + +# APBX bus +apbx0 at mainbus? base 0x80040000 size 0x00040000 + +# APBX DMA +#apbdma1 at apbx? addr 0x80024000 size 0x2000 irq -1 + +# Timers and rotary decoder +timrot0 at apbx? addr 0x80068020 size 0x20 irq 28 +timrot1 at apbx? addr 0x80068040 size 0x20 irq 29 +#timrot2 at apbx? addr 0x80068060 size 0x20 irq 30 +#timrot3 at apbx? addr 0x80068080 size 0x20 irq 31 + +plcom0 at apbx? addr 0x80070000 size 0x1000 irq 0 + +options MEMSIZE=64 +options DDB +options HZ=100 + +options MEMORY_DISK_HOOKS +options MEMORY_DISK_IS_ROOT +options MEMORY_DISK_ROOT_SIZE=12288 # 6 megs +options MEMORY_DISK_RBFLAGS=RB_SINGLE + +pseudo-device md + +file-system FFS diff --git a/sys/arch/evbarm/conf/files.imx23_olinuxino b/sys/arch/evbarm/conf/files.imx23_olinuxino new file mode 100644 index 000000000000..8c28dc870301 --- /dev/null +++ b/sys/arch/evbarm/conf/files.imx23_olinuxino @@ -0,0 +1,10 @@ +# $Id: files.imx23_olinuxino,v 1.1 2012/11/20 19:08:45 jkunz Exp $ +# +# Olimex i.MX23 OLinuXino board configuration info. +# + +# Pull in SoC support +include "arch/arm/imx/files.imx23" + +file arch/evbarm/imx23_olinuxino/imx23_olinuxino_machdep.c + diff --git a/sys/arch/evbarm/conf/mk.imx23_olinuxino b/sys/arch/evbarm/conf/mk.imx23_olinuxino new file mode 100644 index 000000000000..0542e6d601da --- /dev/null +++ b/sys/arch/evbarm/conf/mk.imx23_olinuxino @@ -0,0 +1,7 @@ +# $Id: mk.imx23_olinuxino,v 1.1 2012/11/20 19:08:45 jkunz Exp $ + +SYSTEM_FIRST_OBJ= imx23_olinuxino_start.o +SYSTEM_FIRST_SFILE= ${THISARM}/imx23_olinuxino/imx23_olinuxino_start.S + +KERNEL_BASE_PHYS=0x40000000 +KERNEL_BASE_VIRT=0x40000000 diff --git a/sys/arch/evbarm/conf/std.imx23_olinuxino b/sys/arch/evbarm/conf/std.imx23_olinuxino new file mode 100644 index 000000000000..17f9495e1194 --- /dev/null +++ b/sys/arch/evbarm/conf/std.imx23_olinuxino @@ -0,0 +1,21 @@ +# $Id: std.imx23_olinuxino,v 1.1 2012/11/20 19:08:45 jkunz Exp $ +# +# IMX23_OLINUXINO standard kernel options. + +machine evbarm arm +include "conf/std" # Standard MI options. +include "arch/arm/conf/std.arm" # Standard NetBSD/arm options. + +options EXEC_ELF32 +options CPU_ARM9E + +# To support easy transit to ../arch/arm/arm32 +options ARM32 +options ARM_INTR_IMPL="" +options EVBARM_BOARDTYPE=OLinuXino +options KERNEL_BASE_EXT=0x40000000 + +makeoptions BOARDMKFRAG="${THISARM}/conf/mk.imx23_olinuxino" +makeoptions CPUFLAGS="-march=armv5te -mtune=arm926ej-s" + +include "arch/evbarm/conf/files.imx23_olinuxino" diff --git a/sys/arch/evbarm/imx23_olinuxino/imx23_olinuxino_machdep.c b/sys/arch/evbarm/imx23_olinuxino/imx23_olinuxino_machdep.c new file mode 100644 index 000000000000..41991681b18d --- /dev/null +++ b/sys/arch/evbarm/imx23_olinuxino/imx23_olinuxino_machdep.c @@ -0,0 +1,679 @@ +/* $Id: imx23_olinuxino_machdep.c,v 1.1 2012/11/20 19:08:45 jkunz Exp $ */ + +/* + * Copyright (c) 2012 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Petri Laakso. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include "plcom.h" +#if (NPLCOM > 0) +#include +#include +#endif + +#include "opt_evbarm_boardtype.h" + +static vaddr_t get_ttb(void); +static void setup_real_page_tables(void); +//static void entropy_init(void); + +/* + * Static device map for i.MX23 peripheral address space. + */ +#define _A(a) ((a) & ~L1_S_OFFSET) +#define _S(s) (((s) + L1_S_SIZE - 1) & ~(L1_S_SIZE-1)) +static const struct pmap_devmap imx23_devmap[] = { + { + _A(APBH_BASE), /* Virtual address. */ + _A(APBH_BASE), /* Physical address. */ + _S(APBH_SIZE + APBX_SIZE), /* APBX located after APBH. */ + VM_PROT_READ|VM_PROT_WRITE, /* Protection bits. */ + PTE_NOCACHE /* Cache attributes. */ + }, + { 0, 0, 0, 0, 0 } +}; +#undef _A +#undef _S + +static vm_offset_t physical_freestart; +static vm_offset_t physical_freeend; +static u_int free_pages; +//static rndsave_t imx23_boot_rsp; + +BootConfig bootconfig; +vm_offset_t physical_start; +vm_offset_t physical_end; +char *boot_args; +paddr_t msgbufphys; + +extern char KERNEL_BASE_phys; +extern char KERNEL_BASE_virt; +extern char _end[]; +extern char __data_start[]; +extern char _edata[]; +extern char __bss_start[]; +extern char __bss_end__[]; +extern pv_addr_t kernelstack; + +extern u_int data_abort_handler_address; +extern u_int prefetch_abort_handler_address; + +/* Define various stack sizes in pages. */ +#define FIQ_STACK_SIZE 1 +#define IRQ_STACK_SIZE 1 +#define ABT_STACK_SIZE 1 +#define UND_STACK_SIZE 1 + +/* Macros to translate between physical and virtual addresses. */ +#define KERNEL_BASE_PHYS ((paddr_t)&KERNEL_BASE_phys) +#define KERNEL_BASE_VIRT ((vaddr_t)&KERNEL_BASE_virt) +#define KERN_VTOPHYS(va) \ + ((paddr_t)((vaddr_t)va - KERNEL_BASE_VIRT + KERNEL_BASE_PHYS)) +#define KERN_PHYSTOV(pa) \ + ((vaddr_t)((paddr_t)pa - KERNEL_BASE_PHYS + KERNEL_BASE_VIRT)) + +#define KERNEL_PT_SYS 0 /* L2 table for mapping vectors page. */ +#define KERNEL_PT_KERNEL 1 /* L2 table for mapping kernel. */ +#define KERNEL_PT_KERNEL_NUM 4 + +#define KERNEL_PT_VMDATA (KERNEL_PT_KERNEL + KERNEL_PT_KERNEL_NUM) +/* Page tables for mapping kernel VM */ +#define KERNEL_PT_VMDATA_NUM 4 /* start with 16MB of KVM */ +#define NUM_KERNEL_PTS (KERNEL_PT_VMDATA + KERNEL_PT_VMDATA_NUM) + +pv_addr_t kernel_pt_table[NUM_KERNEL_PTS]; + +#define KERNEL_VM_BASE (KERNEL_BASE + 0x01000000) +#define KERNEL_VM_SIZE (0xf0000000 - KERNEL_VM_BASE) + +#define REG_RD(reg) *(volatile uint32_t *)(reg) +#define REG_WR(reg, val) \ +do { \ + *(volatile uint32_t *)((reg)) = val; \ +} while (0) + +/* + * Initialize everything and return new svc stack pointer. + */ +u_int +initarm(void *arg) +{ + + if (set_cpufuncs()) + panic("set_cpufuncs failed"); + + pmap_devmap_bootstrap(get_ttb(), imx23_devmap); + + cpu_domains((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT); + + consinit(); + //entropy_init(); + + /* Talk to the user. */ +#define BDSTR(s) _BDSTR(s) +#define _BDSTR(s) #s + printf("\nNetBSD/evbarm (" BDSTR(EVBARM_BOARDTYPE) ") booting ...\n"); +#undef BDSTR +#undef _BDSTR + + boot_args[0] = '\0'; + +#ifdef VERBOSE_INIT_ARM + printf("initarm: Configuring system ...\n"); +#endif + + physical_start = DRAM_BASE; + physical_end = DRAM_BASE + MEMSIZE * 1024 * 1024; + physmem = (physical_end - physical_start) / PAGE_SIZE; + + /* bootconfig is used by cpu_dump() and cousins. */ + bootconfig.dramblocks = 1; + bootconfig.dram[0].address = DRAM_BASE; + bootconfig.dram[0].pages = physmem; + + /* + * Our kernel is at the beginning of the DRAM, so set our free space to + * all the memory after the kernel. + */ + physical_freestart = KERN_VTOPHYS(round_page((vaddr_t) _end)); + physical_freeend = physical_end; + free_pages = (physical_freeend - physical_freestart) / PAGE_SIZE; + +#ifdef VERBOSE_INIT_ARM + /* Tell the user about the memory. */ + printf("physmemory: %d pages at 0x%08lx -> 0x%08lx\n", physmem, + physical_start, physical_end - 1); +#endif + + /* + * Set up first and second level page tables. Pages of memory will be + * allocated and mapped for structures required for system operation. + * kernel_l1pt, kernel_pt_table[], systempage, irqstack, abtstack, + * undstack, kernelstack, msgbufphys will be set to point to the memory + * that was allocated for them. + */ + setup_real_page_tables(); + +#ifdef VERBOSE_INIT_ARM + printf("freestart = 0x%08lx, free_pages = %d (0x%08x)\n", + physical_freestart, free_pages, free_pages); +#endif + + uvm_lwp_setuarea(&lwp0, kernelstack.pv_va); + +#ifdef VERBOSE_INIT_ARM + printf("bootstrap done.\n"); +#endif + + /* Copy vectors from page0 to vectors page. */ + arm32_vector_init(ARM_VECTORS_HIGH, ARM_VEC_ALL); +#ifdef VERBOSE_INIT_ARM + printf("init subsystems: stacks "); +#endif + set_stackptr(PSR_FIQ32_MODE, + fiqstack.pv_va + FIQ_STACK_SIZE * PAGE_SIZE); + set_stackptr(PSR_IRQ32_MODE, + irqstack.pv_va + IRQ_STACK_SIZE * PAGE_SIZE); + set_stackptr(PSR_ABT32_MODE, + abtstack.pv_va + ABT_STACK_SIZE * PAGE_SIZE); + set_stackptr(PSR_UND32_MODE, + undstack.pv_va + UND_STACK_SIZE * PAGE_SIZE); +#ifdef VERBOSE_INIT_ARM + printf("vectors "); +#endif + data_abort_handler_address = (u_int)data_abort_handler; + prefetch_abort_handler_address = (u_int)prefetch_abort_handler; + undefined_handler_address = (u_int)undefinedinstruction_bounce; +#ifdef VERBOSE_INIT_ARM + printf("undefined "); +#endif + undefined_init(); + /* Load memory into UVM. */ +#ifdef VERBOSE_INIT_ARM + printf("page "); +#endif + uvm_setpagesize(); + uvm_page_physload(atop(physical_freestart), atop(physical_freeend), + atop(physical_freestart), atop(physical_freeend), + VM_FREELIST_DEFAULT); + + /* Boot strap pmap telling it where the kernel page table is. */ +#ifdef VERBOSE_INIT_ARM + printf("pmap "); +#endif + pmap_bootstrap(KERNEL_VM_BASE, KERNEL_VM_BASE + KERNEL_VM_SIZE); + +#ifdef VERBOSE_INIT_ARM + printf("done.\n"); +#endif + +#ifdef __HAVE_MEMORY_DISK__ + md_root_setconf(memory_disk, sizeof memory_disk); +#endif + +#ifdef BOOTHOWTO + boothowto |= BOOTHOWTO; +#endif + +#ifdef KGDB + if (boothowto & RB_KDB) { + kgdb_debug_init = 1; + kgdb_connect(1); + } +#endif + +#ifdef DDB + db_machine_init(); + if (boothowto & RB_KDB) + Debugger(); +#endif + + return kernelstack.pv_va + USPACE_SVC_STACK_TOP; +} + +/* + * Return TTBR (Translation Table Base Register) value from coprocessor. + */ +static vaddr_t +get_ttb(void) +{ + vaddr_t ttb; + + __asm volatile("mrc p15, 0, %0, c2, c0, 0" : "=r" (ttb)); + + return ttb; +} + +/* + * valloc_pages() is used to allocate free memory to be used for kernel pages. + * Virtual and physical addresses of the allocated memory are saved for the + * later use by the structures: + * + * - kernel_l1pt which holds the address of the kernel's L1 translaton table. + * - kernel_pt_table[] holds the addresses of the kernel's L2 page tables. + * + * pmap_link_l2pt() is used to create link from L1 table entry to the L2 page + * table. Link is a reference to coarse page table which has 256 entries, + * splitting the 1MB that the table describes into 4kB blocks. + * + * pmap_map_entry() updates the PTE in L2 PT for an VA to point to single + * physical page previously allocated. + * + * pmap_map_chunk() maps a chunk of memory using the most efficient + * mapping possible (section, large page, small page) into the provided L1 and + * L2 tables at the specified virtual address. pmap_map_chunk() excepts linking + * to be done before it is called for chunks smaller than a section. + */ +static void +setup_real_page_tables(void) +{ + /* + * Define a macro to simplify memory allocation. As we allocate the + * memory, make sure that we don't walk over our temporary first level + * translation table. + */ +#define valloc_pages(var, np) \ + (var).pv_pa = physical_freestart; \ + physical_freestart += ((np) * PAGE_SIZE); \ + if (physical_freestart > (physical_freeend - L1_TABLE_SIZE)) \ + panic("%s: out of memory", __func__); \ + free_pages -= (np); \ + (var).pv_va = KERN_PHYSTOV((var).pv_pa); \ + memset((char *)(var).pv_va, 0, ((np) * PAGE_SIZE)); + + int loop, pt_index; + + pt_index = 0; + kernel_l1pt.pv_pa = 0; + kernel_l1pt.pv_va = 0; + for (loop = 0; loop <= NUM_KERNEL_PTS; ++loop) { + /* Are we 16kB aligned for an L1? */ + if ((physical_freestart & (L1_TABLE_SIZE - 1)) == 0 && + kernel_l1pt.pv_pa == 0) { + valloc_pages(kernel_l1pt, L1_TABLE_SIZE / PAGE_SIZE); + } else { + valloc_pages(kernel_pt_table[pt_index], + L2_TABLE_SIZE / PAGE_SIZE); + ++pt_index; + } + } + + /* Make sure L1 page table is aligned to 16kB. */ + if (!kernel_l1pt.pv_pa || + (kernel_l1pt.pv_pa & (L1_TABLE_SIZE - 1)) != 0) + panic("%s: Failed to align the kernel page directory", + __func__); + + /* + * Allocate a page for the system page mapped to ARM_VECTORS_HIGH. + * This page will just contain the system vectors and can be shared by + * all processes. + */ + valloc_pages(systempage, 1); + systempage.pv_va = ARM_VECTORS_HIGH; + + /* Allocate stacks for all modes. */ + valloc_pages(fiqstack, FIQ_STACK_SIZE); + valloc_pages(irqstack, IRQ_STACK_SIZE); + valloc_pages(abtstack, ABT_STACK_SIZE); + valloc_pages(undstack, UND_STACK_SIZE); + valloc_pages(kernelstack, UPAGES); + + /* Allocate the message buffer. */ + pv_addr_t msgbuf; + int msgbuf_pgs = round_page(MSGBUFSIZE) / PAGE_SIZE; + valloc_pages(msgbuf, msgbuf_pgs); + msgbufphys = msgbuf.pv_pa; + + vaddr_t l1_va = kernel_l1pt.pv_va; + vaddr_t l1_pa = kernel_l1pt.pv_pa; + + /* Map the L2 pages tables in the L1 page table. */ + + pmap_link_l2pt(l1_va, ARM_VECTORS_HIGH & ~(0x00400000 - 1), + &kernel_pt_table[KERNEL_PT_SYS]); + + for (loop = 0; loop < KERNEL_PT_KERNEL_NUM; loop++) + pmap_link_l2pt(l1_va, KERNEL_BASE + loop * 0x00400000, + &kernel_pt_table[KERNEL_PT_KERNEL + loop]); + + for (loop = 0; loop < KERNEL_PT_VMDATA_NUM; loop++) + pmap_link_l2pt(l1_va, KERNEL_VM_BASE + loop * 0x00400000, + &kernel_pt_table[KERNEL_PT_VMDATA + loop]); + + /* Update the top of the kernel VM. */ + pmap_curmaxkvaddr = + KERNEL_VM_BASE + (KERNEL_PT_VMDATA_NUM * 0x00400000); + + extern char etext[]; + size_t textsize = (uintptr_t)etext - KERNEL_BASE; + size_t totalsize = (uintptr_t)_end - KERNEL_BASE; + u_int logical; + + textsize = (textsize + PGOFSET) & ~PGOFSET; + totalsize = (totalsize + PGOFSET) & ~PGOFSET; + + logical = 0x00000000; /* offset of kernel in RAM */ + + logical += pmap_map_chunk(l1_va, KERNEL_BASE + logical, + physical_start + logical, textsize, + VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); + + logical += pmap_map_chunk(l1_va, KERNEL_BASE + logical, + physical_start + logical, totalsize - textsize, + VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); + + /* Map the stack pages. */ + pmap_map_chunk(l1_va, fiqstack.pv_va, fiqstack.pv_pa, + FIQ_STACK_SIZE * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); + + pmap_map_chunk(l1_va, irqstack.pv_va, irqstack.pv_pa, + IRQ_STACK_SIZE * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); + + pmap_map_chunk(l1_va, abtstack.pv_va, abtstack.pv_pa, + ABT_STACK_SIZE * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); + + pmap_map_chunk(l1_va, undstack.pv_va, undstack.pv_pa, + UND_STACK_SIZE * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); + + pmap_map_chunk(l1_va, kernelstack.pv_va, kernelstack.pv_pa, + UPAGES * PAGE_SIZE, VM_PROT_READ | VM_PROT_WRITE, PTE_CACHE); + + pmap_map_chunk(l1_va, kernel_l1pt.pv_va, kernel_l1pt.pv_pa, + L1_TABLE_SIZE, VM_PROT_READ | VM_PROT_WRITE, PTE_PAGETABLE); + + for (loop = 0; loop < NUM_KERNEL_PTS; ++loop) + pmap_map_chunk(l1_va, kernel_pt_table[loop].pv_va, + kernel_pt_table[loop].pv_pa, L2_TABLE_SIZE, + VM_PROT_READ|VM_PROT_WRITE, PTE_PAGETABLE); + + /* Map the vector page. */ + pmap_map_entry(l1_va, ARM_VECTORS_HIGH, systempage.pv_pa, + VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); + + pmap_devmap_bootstrap(l1_va, imx23_devmap); + +#ifdef VERBOSE_INIT_ARM + /* Tell the user about where all the bits and pieces live. */ + printf("%22s Physical Virtual Num\n", " "); + printf("%22s Starting Ending Starting Ending Pages\n", " "); + + static const char mem_fmt[] = + "%20s: 0x%08lx 0x%08lx 0x%08lx 0x%08lx %d\n"; + static const char mem_fmt_nov[] = + "%20s: 0x%08lx 0x%08lx %d\n"; + + printf(mem_fmt, "SDRAM", physical_start, physical_end-1, + KERN_PHYSTOV(physical_start), KERN_PHYSTOV(physical_end-1), + physmem); + printf(mem_fmt, "text section", + KERN_VTOPHYS(KERNEL_BASE), KERN_VTOPHYS(etext-1), + (vaddr_t)KERNEL_BASE, (vaddr_t)etext-1, + (int)(textsize / PAGE_SIZE)); + printf(mem_fmt, "data section", + KERN_VTOPHYS(__data_start), KERN_VTOPHYS(_edata), + (vaddr_t)__data_start, (vaddr_t)_edata, + (int)((round_page((vaddr_t)_edata) + - trunc_page((vaddr_t)__data_start)) / PAGE_SIZE)); + printf(mem_fmt, "bss section", + KERN_VTOPHYS(__bss_start), KERN_VTOPHYS(__bss_end__), + (vaddr_t)__bss_start, (vaddr_t)__bss_end__, + (int)((round_page((vaddr_t)__bss_end__) + - trunc_page((vaddr_t)__bss_start)) / PAGE_SIZE)); + printf(mem_fmt, "L1 page directory", + kernel_l1pt.pv_pa, kernel_l1pt.pv_pa + L1_TABLE_SIZE - 1, + kernel_l1pt.pv_va, kernel_l1pt.pv_va + L1_TABLE_SIZE - 1, + L1_TABLE_SIZE / PAGE_SIZE); + printf(mem_fmt, "Exception Vectors", + systempage.pv_pa, systempage.pv_pa + PAGE_SIZE - 1, + (vaddr_t)ARM_VECTORS_HIGH, + (vaddr_t)ARM_VECTORS_HIGH + PAGE_SIZE - 1, 1); + printf(mem_fmt, "FIQ stack", + fiqstack.pv_pa, fiqstack.pv_pa + (FIQ_STACK_SIZE * PAGE_SIZE) - 1, + fiqstack.pv_va, fiqstack.pv_va + (FIQ_STACK_SIZE * PAGE_SIZE) - 1, + FIQ_STACK_SIZE); + printf(mem_fmt, "IRQ stack", + irqstack.pv_pa, irqstack.pv_pa + (IRQ_STACK_SIZE * PAGE_SIZE) - 1, + irqstack.pv_va, irqstack.pv_va + (IRQ_STACK_SIZE * PAGE_SIZE) - 1, + IRQ_STACK_SIZE); + printf(mem_fmt, "ABT stack", + abtstack.pv_pa, abtstack.pv_pa + (ABT_STACK_SIZE * PAGE_SIZE) - 1, + abtstack.pv_va, abtstack.pv_va + (ABT_STACK_SIZE * PAGE_SIZE) - 1, + ABT_STACK_SIZE); + printf(mem_fmt, "UND stack", + undstack.pv_pa, undstack.pv_pa + (UND_STACK_SIZE * PAGE_SIZE) - 1, + undstack.pv_va, undstack.pv_va + (UND_STACK_SIZE * PAGE_SIZE) - 1, + UND_STACK_SIZE); + printf(mem_fmt, "SVC stack", + kernelstack.pv_pa, kernelstack.pv_pa + (UPAGES * PAGE_SIZE) - 1, + kernelstack.pv_va, kernelstack.pv_va + (UPAGES * PAGE_SIZE) - 1, + UPAGES); + printf(mem_fmt_nov, "Message Buffer", + msgbufphys, msgbufphys + msgbuf_pgs * PAGE_SIZE - 1, msgbuf_pgs); + printf(mem_fmt, "Free Memory", physical_freestart, physical_freeend-1, + KERN_PHYSTOV(physical_freestart), KERN_PHYSTOV(physical_freeend-1), + free_pages); +#endif + + cpu_domains((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT); + cpu_setttb(l1_pa, FALSE); + cpu_tlb_flushID(); + cpu_domains(DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)); + + return; +} + +/* + * Generate initial random bits for rnd_init(). + */ +#ifdef notyet +static void +entropy_init(void) +{ + uint32_t tmp; + int loop, index; + + /* Test if HW_DIGCTL_ENTROPY is feeding random numbers. */ + tmp = REG_RD(HW_DIGCTL_BASE + HW_DIGCTL_ENTROPY); + if (tmp == REG_RD(HW_DIGCTL_BASE + HW_DIGCTL_ENTROPY)) + return; + + index = 0; + for (loop = 0; loop < RND_SAVEWORDS; loop++) { + imx23_boot_rsp.data[index++] = (uint8_t)(tmp); + imx23_boot_rsp.data[index++] = (uint8_t)(tmp>>8); + imx23_boot_rsp.data[index++] = (uint8_t)(tmp>>16); + imx23_boot_rsp.data[index++] = (uint8_t)(tmp>>24); + imx23_boot_rsp.entropy += 32; + tmp = REG_RD(HW_DIGCTL_BASE + HW_DIGCTL_ENTROPY); + } + + extern rndsave_t *boot_rsp; + boot_rsp = &imx23_boot_rsp; + + return; +} +#endif + +/* + * Initialize console. + */ +static struct plcom_instance imx23_pi = { + .pi_type = PLCOM_TYPE_PL011, + .pi_iot = &imx23_bus_space, + .pi_size = PL011COM_UART_SIZE, + .pi_iobase = HW_UARTDBG_BASE +}; + +#define PLCONMODE ((TTYDEF_CFLAG & ~(CSIZE | CSTOPB | PARENB)) | CS8) /* 8N1 */ +#define PLCONSPEED 115200 +void +consinit(void) +{ + /* consinit() is called from also from the main(). */ + static int consinit_called = 0; + + if (consinit_called) + return; + + plcomcnattach(&imx23_pi, PLCONSPEED, IMX23_UART_CLK, PLCONMODE, 0); + + consinit_called = 1; + + return; +} + +/* + * Reboot or halt the system. + */ +void +cpu_reboot(int howto, char *bootstr) +{ + static int cpu_reboot_called = 0; + + boothowto |= howto; + + /* + * If this is the first invocation of cpu_reboot() and the RB_NOSYNC + * flag is not set in howto; sync and unmount the system disks by + * calling vfs_shutdown(9) and set the time of day clock by calling + * resettodr(9). + */ + if (!cpu_reboot_called && !(boothowto & RB_NOSYNC)) { + vfs_shutdown(); + resettodr(); + } + + cpu_reboot_called = 1; + + IRQdisable; /* FIQ's stays on because they are special. */ + + /* + * If rebooting after a crash (i.e., if RB_DUMP is set in howto, but + * RB_HALT is not), save a system crash dump. + */ + if ((boothowto & RB_DUMP) && !(boothowto & RB_HALT)) + panic("please implement crash dump!"); // XXX + + /* Run any shutdown hooks by calling pmf_system_shutdown(9). */ + pmf_system_shutdown(boothowto); + + printf("system %s.\n", boothowto & RB_HALT ? "halted" : "rebooted"); + + if (boothowto & RB_HALT) { + /* Enable i.MX233 wait-for-interrupt mode. */ + REG_WR(HW_CLKCTRL_BASE + HW_CLKCTRL_CPU, + (REG_RD(HW_CLKCTRL_BASE + HW_CLKCTRL_CPU) | + HW_CLKCTRL_CPU_INTERRUPT_WAIT)); + + /* Disable FIQ's and wait for interrupt (which never arrives) */ + __asm volatile( \ + "mrs r0, cpsr\n\t" \ + "orr r0, #0x40\n\t" \ + "msr cpsr_c, r0\n\t" \ + "mov r0, #0\n\t" \ + "mcr p15, 0, r0, c7, c0, 4\n\t" + ); + + for(;;); + + /* NOT REACHED */ + } + + /* Reboot the system. */ + REG_WR(HW_RTC_BASE + HW_RTC_WATCHDOG, 10000); + REG_WR(HW_RTC_BASE + HW_RTC_CTRL_SET, HW_RTC_CTRL_WATCHDOGEN); + REG_WR(HW_RTC_BASE + HW_RTC_WATCHDOG, 0); + + for(;;); + + /* NOT REACHED */ +} + +/* + * Delay us microseconds. + */ +void +delay(unsigned int us) +{ + uint32_t start; + uint32_t now; + uint32_t elapsed; + uint32_t total; + uint32_t last; + + total = 0; + last = 0; + start = REG_RD(HW_DIGCTL_BASE + HW_DIGCTL_MICROSECONDS); + + do { + now = REG_RD(HW_DIGCTL_BASE + HW_DIGCTL_MICROSECONDS); + + if (start <= now) + elapsed = now - start; + else /* Take care of overflow. */ + elapsed = (UINT32_MAX - start) + 1 + now; + + total += elapsed - last; + last = elapsed; + + } while (total < us); + + return; +} diff --git a/sys/arch/evbarm/imx23_olinuxino/imx23_olinuxino_start.S b/sys/arch/evbarm/imx23_olinuxino/imx23_olinuxino_start.S new file mode 100644 index 000000000000..32548d43a59c --- /dev/null +++ b/sys/arch/evbarm/imx23_olinuxino/imx23_olinuxino_start.S @@ -0,0 +1,185 @@ +/* $Id: imx23_olinuxino_start.S,v 1.1 2012/11/20 19:08:46 jkunz Exp $ */ + +/* + * Copyright (c) 2012 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Petri Laakso. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include + +.section .start,"ax",%progbits + +.global _C_LABEL(olinuxino_start) +_C_LABEL(olinuxino_start): + + /* + * Set up the first level page table. The page table has 4096 section + * page table entries which each one maps 1MB of virtual memory. + * Section entries are mapped from mmu_init_table to the page table. + */ + l1pt_p .req r0 + mit_p .req r1 + va .req r2 + pa .req r3 + n_sec .req r4 + attr .req r5 + pte_p .req r6 + sec .req r7 + tmp .req r8 + tmp2 .req r9 + + ldr l1pt_p, Ll1_pt + + /* Zero the page table. */ + mov tmp, #0 + add tmp2, l1pt_p, #L1_TABLE_SIZE +1: str tmp, [l1pt_p], #4 + cmp l1pt_p, tmp2 + blt 1b + + ldr l1pt_p, Ll1_pt + + /* Map sections. */ + ldr mit_p, =mmu_init_table + ldmia mit_p!, {va, pa, n_sec, attr} + + /* + * Calculate PTE addresses for a MVA's. + * + * Bits[31:14] of the Translation Table Base register are concatenated + * with bits[31:20] of the modified virtual address and two zero bits + * to produce a physical address of the page table entry for a MVA: + * + * PTE = (TTBR & 0xffffc000) | ((MVA & 0xfff00000)>>18) + */ +3: ldr tmp, =0xffffc000 + and pte_p, l1pt_p, tmp + ldr tmp, =0xfff00000 + and va, va, tmp + mov va, va, LSR #18 + orr pte_p, pte_p, va + +2: orr sec, pa, attr + str sec, [pte_p], #4 /* Store #n_sec sections to the page */ + add pa, pa, #0x100000 /* table. */ + subs n_sec, #1 + bne 2b + + ldmia mit_p!, {va, pa, n_sec, attr} + cmp n_sec, #0 + bne 3b + + /* + * The Translation Table Base Register holds the physical address of + * the page table. + */ + mcr p15, 0, l1pt_p, c2, c0, 0 + + .unreq l1pt_p + .unreq mit_p + .unreq va + .unreq pa + .unreq n_sec + .unreq attr + .unreq pte_p + .unreq sec + .unreq tmp + .unreq tmp2 + + /* + * Sections are in domain 0 and we set D0 access control to client + * mode, which means AP bits are checked. Since we are running + * privileged mode and APs are kernel read/write, access is granted. + */ + mov r0, #DOMAIN_CLIENT<<(PMAP_DOMAIN_KERNEL*2) + mcr p15, 0, r0, c3, c0, 0 + + /* + * Enable the MMU. + */ + mov r0, #0 + mcr p15, 0, r0, c8, c7, 0 /* Invalidate TLB. */ + + mrc p15, 0, r0, c1, c0, 0 + ldr r1, =(CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE \ + | CPU_CONTROL_AFLT_ENABLE | CPU_CONTROL_MMU_ENABLE) + orr r0, r0, r1 + mcr p15, 0, r0, c1, c0, 0 + nop /* Fetch flat. */ + nop /* Fetch flat. */ + + /* + * Jump to start in locore.S. start sets the sp point to DRAM, zeroes + * the .bss and calls initarm. start never returns. + */ + ldr pc, =start + + /* NOTREACHED */ + +/* + * Initial first level translation table on a 16kB boundary located at the + * end of the DRAM. + * + * The translation table has 4096 32-bit section entries, each describing 1MB of + * virtual memory which means 4GB of virtual memory to be addressed. + */ +Ll1_pt: + .word (DRAM_BASE + MEMSIZE * 1024 * 1024 - L1_TABLE_SIZE) + +#define MMU_INIT(va,pa,n_sec,attr) \ + .word va; \ + .word pa; \ + .word n_sec; \ + .word attr; + +mmu_init_table: + /* On-chip RAM */ + MMU_INIT(0x00000000, 0x00000000, + 1, + L1_S_AP(AP_KRW) | L1_S_DOM(PMAP_DOMAIN_KERNEL) | L1_S_PROTO) + + /* On-chip ROM (Vectors) */ + MMU_INIT(0xFFFF0000, 0xFFFF0000, + 1, + L1_S_AP(AP_KRW) | L1_S_DOM(PMAP_DOMAIN_KERNEL) | L1_S_PROTO) + + /* DRAM */ + MMU_INIT(KERNEL_BASE_virt, KERNEL_BASE_phys, + MEMSIZE, + L1_S_AP(AP_KRW) | L1_S_DOM(PMAP_DOMAIN_KERNEL) | L1_S_C |\ + L1_S_B | L1_S_PROTO) + + /* Peripherals */ + MMU_INIT(APBH_BASE, APBH_BASE, + 1, + L1_S_AP(AP_KRW) | L1_S_DOM(PMAP_DOMAIN_KERNEL) | L1_S_PROTO) + + MMU_INIT(0, 0, 0, 0) diff --git a/sys/arch/evbarm/stand/Makefile b/sys/arch/evbarm/stand/Makefile index 4fcb58d4f62b..6aa0b90958f9 100644 --- a/sys/arch/evbarm/stand/Makefile +++ b/sys/arch/evbarm/stand/Makefile @@ -1,6 +1,7 @@ -# $NetBSD: Makefile,v 1.2 2012/01/30 03:28:34 nisimura Exp $ +# $NetBSD: Makefile,v 1.3 2012/11/20 19:17:03 jkunz Exp $ SUBDIR+= gzboot SUBDIR+= boot2440 +SUBDIR+= bootimx23 .include diff --git a/sys/arch/evbarm/stand/bootimx23/Makefile b/sys/arch/evbarm/stand/bootimx23/Makefile new file mode 100644 index 000000000000..b0fc8947236b --- /dev/null +++ b/sys/arch/evbarm/stand/bootimx23/Makefile @@ -0,0 +1,52 @@ +# $Id: Makefile,v 1.1 2012/11/20 19:08:46 jkunz Exp $ + +S= ${.CURDIR}/../../../../ +PROG= bootimx23 +SRCS= boot_prep.c power_prep.c clock_prep.c emi_prep.c \ + pinctrl_prep.c common.c + +.include + +CLEANFILES+= ${PROG} +CFLAGS+= -Wall -Wno-main -ffreestanding -march=armv5te -mtune=arm926ej-s +CPPFLAGS+= -D_STANDALONE +CPPFLAGS+= -nostdinc -I. -I${.CURDIR} -I${.OBJDIR} -I${S} -I${S}/arch +#CPPFLAGS+= -DDEBUG +#DBG= -g + +LIBCRT0= # nothing +LIBCRTBEGIN= # nothing +LIBCRTEND= # nothing +LIBC= # nothing + +MAN= # no manual page +NOMAN= # defined +STRIPFLAG= +BINMODE= 444 + +RELOC= 0x00000000 +ENTRY= _start + +### find out what to use for libkern +KERN_AS= library +.include "${S}/lib/libkern/Makefile.inc" +LIBKERN= ${KERNLIB} + +### find out what to use for libsa +SA_AS= library +.include "${S}/lib/libsa/Makefile.inc" +LIBSA= ${SALIB} + +${PROG}: ${OBJS} ${LIBSA} ${LIBKERN} + ${LD} -N -Ttext ${RELOC} -Bstatic -e ${ENTRY} -o ${.TARGET} \ + ${OBJS} ${LIBSA} ${LIBKERN} + + +cleandir distclean: .WAIT cleanlibdir + +cleanlibdir: + -rm -rf lib + +.include +.include + diff --git a/sys/arch/evbarm/stand/bootimx23/boot_prep.c b/sys/arch/evbarm/stand/bootimx23/boot_prep.c new file mode 100644 index 000000000000..5b3b2d3d552a --- /dev/null +++ b/sys/arch/evbarm/stand/bootimx23/boot_prep.c @@ -0,0 +1,68 @@ +/* $Id: boot_prep.c,v 1.1 2012/11/20 19:08:46 jkunz Exp $ */ + +/* + * Copyright (c) 2012 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Petri Laakso. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#include + +#include + +#include "common.h" + +/* + * Initialize i.MX23 power, clock and DRAM. + */ +int +_start(void) +{ + + /* Make sure timer is running */ + REG_WRITE(HW_DIGCTL_BASE + HW_DIGCTL_CTRL_CLR, + HW_DIGCTL_CTRL_XTAL24M_GATE); + + printf("\n\rBooting"); + + power_prep(); + putchar('.'); + + clock_prep(); + putchar('.'); + + pinctrl_prep(); + delay_us(1000); + putchar('.'); + + emi_prep(); + printf("done.\n\r"); + + return 0; +} diff --git a/sys/arch/evbarm/stand/bootimx23/bootimx23.bd b/sys/arch/evbarm/stand/bootimx23/bootimx23.bd new file mode 100644 index 000000000000..3bd0a2987cff --- /dev/null +++ b/sys/arch/evbarm/stand/bootimx23/bootimx23.bd @@ -0,0 +1,31 @@ +/* $Id: bootimx23.bd,v 1.1 2012/11/20 19:08:46 jkunz Exp $ */ + +/* + * elftosb command file. + * + * Generate boot image by issuing: + * $ elftosb -V -c bootimx23.bd -z -o bootimx23.sb + * + * Verify generated boot image: + * $ sbtool -x 2 bootimx23.sb + * + */ + +options { + toolset = "GNU"; +} + +sources { + boot_prep="./boot_prep.elf"; + netbsd="./netbsd"; +} + +section (0) { + // Initialize power, clocks and DRAM. + load boot_prep; + call boot_prep; + + // Load and start NetBSD kernel. + load netbsd; + jump netbsd; +} diff --git a/sys/arch/evbarm/stand/bootimx23/clock_prep.c b/sys/arch/evbarm/stand/bootimx23/clock_prep.c new file mode 100644 index 000000000000..eac4707dd89a --- /dev/null +++ b/sys/arch/evbarm/stand/bootimx23/clock_prep.c @@ -0,0 +1,255 @@ +/* $Id: clock_prep.c,v 1.1 2012/11/20 19:08:46 jkunz Exp $ */ + +/* + * Copyright (c) 2012 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Petri Laakso. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include + +#include + +#include + +#include "common.h" + +void enable_pll(void); +void enable_ref_cpu(int); +void enable_ref_emi(int); +void enable_ref_io(int); +void use_ref_cpu(void); +void use_ref_emi(void); +void use_ref_io(void); +void set_hbus_div(int); +void set_emi_div(int); +void set_ssp_div(int); + +/* Clock frequences after clock_prep() */ +#define CPU_FRAC 0x13 /* CPUCLK @ 454.74 MHz */ +#define HBUS_DIV 0x3 /* AHBCLK @ 151.58 MHz */ +#define EMI_FRAC 0x21 /* EMICLK @ 130.91 MHz */ +#define EMI_DIV 0x2 +#define IO_FRAC 0x12 /* IOCLK @ 480.00 MHz */ +#define SSP_DIV 0x5 /* SSPCLK @ 96.00 MHz */ + +/* Offset to frac register for byte store instructions. (strb) */ +#define HW_CLKCTRL_FRAC_CPU (HW_CLKCTRL_FRAC+0) +#define HW_CLKCTRL_FRAC_EMI (HW_CLKCTRL_FRAC+1) +#define HW_CLKCTRL_FRAC_IO (HW_CLKCTRL_FRAC+3) + +#define CLKCTRL_RD(reg) *(volatile uint32_t *)((HW_CLKCTRL_BASE) + (reg)) +#define CLKCTRL_WR(reg, val) \ +do { \ + *(volatile uint32_t *)((HW_CLKCTRL_BASE) + (reg)) = val; \ +} while (0) +#define CLKCTRL_WR_BYTE(reg, val) \ +do { \ + *(volatile uint8_t *)((HW_CLKCTRL_BASE) + (reg)) = val; \ +} while (0) + +/* + * Initializes fast PLL based clocks for CPU, HBUS and DRAM. + */ +int +clock_prep(void) +{ + + enable_pll(); + enable_ref_cpu(CPU_FRAC); + enable_ref_emi(EMI_FRAC); + enable_ref_io(IO_FRAC); + set_emi_div(EMI_DIV); + set_hbus_div(HBUS_DIV); + delay_us(1000); + use_ref_cpu(); + //delay_us(1000); + use_ref_emi(); + use_ref_io(); + set_ssp_div(SSP_DIV); + + return 0; +} + +/* + * Turn PLL on and wait until it's locked to 480 MHz. + */ +void +enable_pll(void) +{ + + CLKCTRL_WR(HW_CLKCTRL_PLLCTRL0_SET, HW_CLKCTRL_PLLCTRL0_POWER); + while (!(CLKCTRL_RD(HW_CLKCTRL_PLLCTRL1) & HW_CLKCTRL_PLLCTRL1_LOCK)); + + return; +} + +/* + * Enable fractional divider clock ref_cpu with divide value "frac". + */ +void +enable_ref_cpu(int frac) +{ + uint32_t reg; + + reg = CLKCTRL_RD(HW_CLKCTRL_FRAC); + reg &= ~(HW_CLKCTRL_FRAC_CLKGATECPU | HW_CLKCTRL_FRAC_CPUFRAC); + reg |= __SHIFTIN(frac, HW_CLKCTRL_FRAC_CPUFRAC); + CLKCTRL_WR_BYTE(HW_CLKCTRL_FRAC_CPU, reg); + + return; +} + +/* + * Enable fractional divider clock ref_emi with divide value "frac". + */ +void +enable_ref_emi(int frac) +{ + uint32_t reg; + + reg = CLKCTRL_RD(HW_CLKCTRL_FRAC); + reg &= ~(HW_CLKCTRL_FRAC_CLKGATEEMI | HW_CLKCTRL_FRAC_EMIFRAC); + reg |= __SHIFTIN(frac, HW_CLKCTRL_FRAC_EMIFRAC); + CLKCTRL_WR_BYTE(HW_CLKCTRL_FRAC_EMI, (reg >> 8)); + + return; +} + +/* + * Enable fractional divider clock ref_io with divide value "frac". + */ +void +enable_ref_io(int frac) +{ + uint32_t reg; + + reg = CLKCTRL_RD(HW_CLKCTRL_FRAC); + reg &= ~(HW_CLKCTRL_FRAC_CLKGATEIO | HW_CLKCTRL_FRAC_IOFRAC); + reg |= __SHIFTIN(frac, HW_CLKCTRL_FRAC_IOFRAC); + CLKCTRL_WR_BYTE(HW_CLKCTRL_FRAC_IO, (reg >> 24)); + + return; +} + +/* + * Divide CLK_P by "div" to get CLK_H frequency. + */ +void +set_hbus_div(int div) +{ + uint32_t reg; + + reg = CLKCTRL_RD(HW_CLKCTRL_HBUS); + reg &= ~(HW_CLKCTRL_HBUS_DIV); + reg |= __SHIFTIN(div, HW_CLKCTRL_HBUS_DIV); + while (CLKCTRL_RD(HW_CLKCTRL_HBUS) & HW_CLKCTRL_HBUS_BUSY); + CLKCTRL_WR(HW_CLKCTRL_HBUS, reg); + + return; +} + +/* + * ref_emi is divied "div" to get CLK_EMI. + */ +void +set_emi_div(int div) +{ + uint32_t reg; + + reg = CLKCTRL_RD(HW_CLKCTRL_EMI); + reg &= ~(HW_CLKCTRL_EMI_DIV_EMI); + reg |= __SHIFTIN(div, HW_CLKCTRL_EMI_DIV_EMI); + CLKCTRL_WR(HW_CLKCTRL_EMI, reg); + + return; +} + +/* + * ref_io is divied "div" to get CLK_SSP. + */ +void +set_ssp_div(int div) +{ + uint32_t reg; + + reg = CLKCTRL_RD(HW_CLKCTRL_SSP); + reg &= ~(HW_CLKCTRL_SSP_DIV); + reg |= __SHIFTIN(div, HW_CLKCTRL_SSP_DIV); + CLKCTRL_WR(HW_CLKCTRL_SSP, reg); + + return; +} + +/* + * Transition from ref_xtal to use ref_cpu. + */ +void +use_ref_cpu(void) +{ + CLKCTRL_WR(HW_CLKCTRL_CLKSEQ_CLR, HW_CLKCTRL_CLKSEQ_BYPASS_CPU); + return; +} + +/* + * Transition from ref_xtal to use ref_emi and source CLK_EMI from ref_emi. + */ +void +use_ref_emi(void) +{ + uint32_t reg; + + /* Enable ref_emi. */ + CLKCTRL_WR(HW_CLKCTRL_CLKSEQ_CLR, HW_CLKCTRL_CLKSEQ_BYPASS_EMI); + + /* CLK_EMI sourced by the ref_emi. */ + reg = CLKCTRL_RD(HW_CLKCTRL_EMI); + reg &= ~(HW_CLKCTRL_EMI_CLKGATE); + CLKCTRL_WR(HW_CLKCTRL_EMI, reg); + + return; +} + +/* + * Transition from ref_xtal to use ref_io and source CLK_SSP from ref_io. + */ +void +use_ref_io(void) +{ + uint32_t reg; + + /* Enable ref_io for SSP. */ + CLKCTRL_WR(HW_CLKCTRL_CLKSEQ_CLR, HW_CLKCTRL_CLKSEQ_BYPASS_SSP); + + /* CLK_SSP sourced by the ref_io. */ + reg = CLKCTRL_RD(HW_CLKCTRL_SSP); + reg &= ~(HW_CLKCTRL_SSP_CLKGATE); + CLKCTRL_WR(HW_CLKCTRL_SSP, reg); + + return; +} diff --git a/sys/arch/evbarm/stand/bootimx23/common.c b/sys/arch/evbarm/stand/bootimx23/common.c new file mode 100644 index 000000000000..75bc4f934803 --- /dev/null +++ b/sys/arch/evbarm/stand/bootimx23/common.c @@ -0,0 +1,69 @@ +/* $Id: common.c,v 1.1 2012/11/20 19:08:46 jkunz Exp $ */ + +/* + * Copyright (c) 2012 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Petri Laakso. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#include +#include + +#include "common.h" + +/* + * Delay "delay" microseconds. + */ +void +delay_us(unsigned int delay) +{ + + /* Set microsecond timer to 0 */ + REG_WRITE(HW_DIGCTL_BASE + HW_DIGCTL_MICROSECONDS_CLR, 0xFFFFFFFF); + + while (REG_READ(HW_DIGCTL_BASE + HW_DIGCTL_MICROSECONDS) < delay); + + return; +} + +/* + * Write character to debug UART. + */ +void +putchar(int ch) +{ + + /* Wait until transmit FIFO has space for the new character. */ + while (REG_READ(HW_UARTDBG_BASE + HW_UARTDBGFR) & HW_UARTDBGFR_TXFF); + + REG_WRITE_BYTE(HW_UARTDBG_BASE + HW_UARTDBGDR, + __SHIFTIN(ch, HW_UARTDBGDR_DATA)); + + return; +} diff --git a/sys/arch/evbarm/stand/bootimx23/common.h b/sys/arch/evbarm/stand/bootimx23/common.h new file mode 100644 index 000000000000..e9404d03ae56 --- /dev/null +++ b/sys/arch/evbarm/stand/bootimx23/common.h @@ -0,0 +1,52 @@ +/* $Id: common.h,v 1.1 2012/11/20 19:08:46 jkunz Exp $ */ + +/* + * Copyright (c) 2012 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Petri Laakso. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _BOOTIMX23_COMMON_ +#define _BOOTIMX23_COMMON_ + +#define REG_READ(reg) *(volatile uint32_t *)(reg) +#define REG_WRITE(reg, val) \ +do { \ + *(volatile uint32_t *)((reg)) = val; \ +} while (0) +#define REG_WRITE_BYTE(reg, val) \ +do { \ + *(volatile uint8_t *)((reg)) = val; \ +} while (0) + +int clock_prep(void); +int emi_prep(void); +int pinctrl_prep(void); +int power_prep(void); +void delay_us(unsigned int); +void putchar(int); + +#endif /* !_BOOTIMX23_COMMON_ */ diff --git a/sys/arch/evbarm/stand/bootimx23/emi_prep.c b/sys/arch/evbarm/stand/bootimx23/emi_prep.c new file mode 100644 index 000000000000..e987e3db6467 --- /dev/null +++ b/sys/arch/evbarm/stand/bootimx23/emi_prep.c @@ -0,0 +1,151 @@ +/* $Id: emi_prep.c,v 1.1 2012/11/20 19:08:46 jkunz Exp $ */ + +/* + * Copyright (c) 2012 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Petri Laakso. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include + +#include + +#include + +#include "common.h" + +void init_dram_registers(void); +void start_dram(void); +uint32_t get_dram_int_status(void); + +/* + * Initialize external DRAM memory. + */ +int +emi_prep(void) +{ + + init_dram_registers(); + start_dram(); + + return 0; +} + +/* + * DRAM register values for 32Mx16 hy5du121622dtp-d43 DDR module. + * + * Register values were copied from Freescale's imx-bootlets-src-10.05.02 + * source code, init_ddr_mt46v32m16_133Mhz() function. Only change to those + * settings were to HW_DRAM_CTL19_DQS_OUT_SHIFT which was set to 16 as a result + * from trial and error. + */ +void +init_dram_registers(void) +{ + uint32_t reg; + + REG_WRITE(HW_DRAM_BASE + HW_DRAM_CTL00, 0x01010001); + REG_WRITE(HW_DRAM_BASE + HW_DRAM_CTL01, 0x00010100); + REG_WRITE(HW_DRAM_BASE + HW_DRAM_CTL02, 0x01000101); + REG_WRITE(HW_DRAM_BASE + HW_DRAM_CTL03, 0x00000001); + REG_WRITE(HW_DRAM_BASE + HW_DRAM_CTL04, 0x00000101); + REG_WRITE(HW_DRAM_BASE + HW_DRAM_CTL05, 0x00000000); + REG_WRITE(HW_DRAM_BASE + HW_DRAM_CTL06, 0x00010000); + REG_WRITE(HW_DRAM_BASE + HW_DRAM_CTL07, 0x01000001); + // HW_DRAM_CTL08 initialized last. + REG_WRITE(HW_DRAM_BASE + HW_DRAM_CTL09, 0x00000001); + REG_WRITE(HW_DRAM_BASE + HW_DRAM_CTL10, 0x07000200); + REG_WRITE(HW_DRAM_BASE + HW_DRAM_CTL11, 0x00070202); + REG_WRITE(HW_DRAM_BASE + HW_DRAM_CTL12, 0x02020000); + REG_WRITE(HW_DRAM_BASE + HW_DRAM_CTL13, 0x04040a01); + REG_WRITE(HW_DRAM_BASE + HW_DRAM_CTL14, 0x00000201); + REG_WRITE(HW_DRAM_BASE + HW_DRAM_CTL15, 0x02040000); + REG_WRITE(HW_DRAM_BASE + HW_DRAM_CTL16, 0x02000000); + REG_WRITE(HW_DRAM_BASE + HW_DRAM_CTL17, 0x19000f08); + REG_WRITE(HW_DRAM_BASE + HW_DRAM_CTL18, 0x0d0d0000); +// REG_WRITE(HW_DRAM_BASE + HW_DRAM_CTL19, 0x02021313); + reg = __SHIFTIN(2, HW_DRAM_CTL19_DQS_OUT_SHIFT_BYPASS) | + __SHIFTIN(16, HW_DRAM_CTL19_DQS_OUT_SHIFT) | + __SHIFTIN(19, HW_DRAM_CTL19_DLL_DQS_DELAY_BYPASS_1) | + __SHIFTIN(19, HW_DRAM_CTL19_DLL_DQS_DELAY_BYPASS_0); + REG_WRITE(HW_DRAM_BASE + HW_DRAM_CTL19, reg); + REG_WRITE(HW_DRAM_BASE + HW_DRAM_CTL20, 0x02061521); + REG_WRITE(HW_DRAM_BASE + HW_DRAM_CTL21, 0x0000000a); + REG_WRITE(HW_DRAM_BASE + HW_DRAM_CTL22, 0x00080008); + REG_WRITE(HW_DRAM_BASE + HW_DRAM_CTL23, 0x00200020); + REG_WRITE(HW_DRAM_BASE + HW_DRAM_CTL24, 0x00200020); + REG_WRITE(HW_DRAM_BASE + HW_DRAM_CTL25, 0x00200020); + REG_WRITE(HW_DRAM_BASE + HW_DRAM_CTL26, 0x000003f7); + // HW_DRAM_CTL27 + // HW_DRAM_CTL28 + REG_WRITE(HW_DRAM_BASE + HW_DRAM_CTL29, 0x00000020); + REG_WRITE(HW_DRAM_BASE + HW_DRAM_CTL30, 0x00000020); + REG_WRITE(HW_DRAM_BASE + HW_DRAM_CTL31, 0x00c80000); + REG_WRITE(HW_DRAM_BASE + HW_DRAM_CTL32, 0x000a23cd); + REG_WRITE(HW_DRAM_BASE + HW_DRAM_CTL33, 0x000000c8); + REG_WRITE(HW_DRAM_BASE + HW_DRAM_CTL34, 0x00006665); + // HW_DRAM_CTL35 is read only register + REG_WRITE(HW_DRAM_BASE + HW_DRAM_CTL36, 0x00000101); + REG_WRITE(HW_DRAM_BASE + HW_DRAM_CTL37, 0x00040001); + REG_WRITE(HW_DRAM_BASE + HW_DRAM_CTL38, 0x00000000); + REG_WRITE(HW_DRAM_BASE + HW_DRAM_CTL39, 0x00000000); + REG_WRITE(HW_DRAM_BASE + HW_DRAM_CTL40, 0x00010000); + REG_WRITE(HW_DRAM_BASE + HW_DRAM_CTL08, 0x01000000); + + return; +} + +/* + * Start DRAM module. After return DRAM is ready to use. + */ +void +start_dram(void) +{ + uint32_t reg; + + reg = REG_READ(HW_DRAM_BASE + HW_DRAM_CTL08); + reg |= HW_DRAM_CTL08_START; + REG_WRITE(HW_DRAM_BASE + HW_DRAM_CTL08, reg); + + /* Wait until DRAM initialization is complete. */ + while(!(get_dram_int_status() & (1<<2))); + + return; +} + +/* + * Return DRAM controller interrupt status register. + */ +uint32_t +get_dram_int_status(void) +{ + uint32_t reg; + + reg = REG_READ(HW_DRAM_BASE + HW_DRAM_CTL18); + return __SHIFTOUT(reg, HW_DRAM_CTL18_INT_STATUS); +} diff --git a/sys/arch/evbarm/stand/bootimx23/pinctrl_prep.c b/sys/arch/evbarm/stand/bootimx23/pinctrl_prep.c new file mode 100644 index 000000000000..4226c9f657ba --- /dev/null +++ b/sys/arch/evbarm/stand/bootimx23/pinctrl_prep.c @@ -0,0 +1,485 @@ +/* $Id: pinctrl_prep.c,v 1.1 2012/11/20 19:08:46 jkunz Exp $ */ + +/* + * Copyright (c) 2012 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Petri Laakso. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include + +#include + +#include + +#include "common.h" + +void configure_emi_mux(void); +void configure_emi_drive(int); +void disable_emi_padkeepers(void); +void configure_ssp_mux(); +void configure_ssp_drive(int); +void configure_ssp_pullups(void); + +/* EMI pins output drive strengths */ +#define DRIVE_04_MA 0x0 /* 4 mA */ +#define DRIVE_08_MA 0x1 /* 8 mA */ +#define DRIVE_12_MA 0x2 /* 12 mA */ +#define DRIVE_16_MA 0x3 /* 16 mA */ + +/* + * Configure external EMI pins. + */ +int +pinctrl_prep(void) +{ + + REG_WRITE(HW_PINCTRL_BASE + HW_PINCTRL_CTRL_CLR, + (HW_PINCTRL_CTRL_SFTRST | HW_PINCTRL_CTRL_CLKGATE)); + + /* EMI. */ + configure_emi_mux(); + configure_emi_drive(DRIVE_12_MA); + disable_emi_padkeepers(); + + /* SSP. */ + configure_ssp_mux(); + configure_ssp_drive(DRIVE_16_MA); + configure_ssp_pullups(); + + return 0; +} + +/* + * Configure external EMI pins to be used for DRAM. + */ +void +configure_emi_mux(void) +{ + + REG_WRITE(HW_PINCTRL_BASE + HW_PINCTRL_MUXSEL4_CLR, ( + HW_PINCTRL_MUXSEL4_BANK2_PIN15 | /* Pin 108, EMI_A06 */ + HW_PINCTRL_MUXSEL4_BANK2_PIN14 | /* Pin 107, EMI_A05 */ + HW_PINCTRL_MUXSEL4_BANK2_PIN13 | /* Pin 109, EMI_A04 */ + HW_PINCTRL_MUXSEL4_BANK2_PIN12 | /* Pin 110, EMI_A03 */ + HW_PINCTRL_MUXSEL4_BANK2_PIN11 | /* Pin 111, EMI_A02 */ + HW_PINCTRL_MUXSEL4_BANK2_PIN10 | /* Pin 112, EMI_A01 */ + HW_PINCTRL_MUXSEL4_BANK2_PIN09) /* Pin 113, EMI_A00 */ + ); + + REG_WRITE(HW_PINCTRL_BASE + HW_PINCTRL_MUXSEL5_CLR, ( + HW_PINCTRL_MUXSEL5_BANK2_PIN31 | /* Pin 114, EMI_WEN */ + HW_PINCTRL_MUXSEL5_BANK2_PIN30 | /* Pin 98, EMI_RASN */ + HW_PINCTRL_MUXSEL5_BANK2_PIN29 | /* Pin 115, EMI_CKE */ +#if 0 + /* 169-Pin BGA Package */ + HW_PINCTRL_MUXSEL5_BANK2_PIN26 | /* Pin 99, EMI_CE1N */ +#endif + HW_PINCTRL_MUXSEL5_BANK2_PIN25 | /* Pin 100, EMI_CE0N */ + HW_PINCTRL_MUXSEL5_BANK2_PIN24 | /* Pin 97, EMI_CASN */ + HW_PINCTRL_MUXSEL5_BANK2_PIN23 | /* Pin 117, EMI_BA1 */ + HW_PINCTRL_MUXSEL5_BANK2_PIN22 | /* Pin 116, EMI_BA0 */ + HW_PINCTRL_MUXSEL5_BANK2_PIN21 | /* Pin 101, EMI_A12 */ + HW_PINCTRL_MUXSEL5_BANK2_PIN20 | /* Pin 102, EMI_A11 */ + HW_PINCTRL_MUXSEL5_BANK2_PIN19 | /* Pin 104, EMI_A10 */ + HW_PINCTRL_MUXSEL5_BANK2_PIN18 | /* Pin 103, EMI_A09 */ + HW_PINCTRL_MUXSEL5_BANK2_PIN17 | /* Pin 106, EMI_A08 */ + HW_PINCTRL_MUXSEL5_BANK2_PIN16) /* Pin 105, EMI_A07 */ + ); + + REG_WRITE(HW_PINCTRL_BASE + HW_PINCTRL_MUXSEL6_CLR, ( + HW_PINCTRL_MUXSEL6_BANK3_PIN15 | /* Pin 95, EMI_D15 */ + HW_PINCTRL_MUXSEL6_BANK3_PIN14 | /* Pin 96, EMI_D14 */ + HW_PINCTRL_MUXSEL6_BANK3_PIN13 | /* Pin 94, EMI_D13 */ + HW_PINCTRL_MUXSEL6_BANK3_PIN12 | /* Pin 93, EMI_D12 */ + HW_PINCTRL_MUXSEL6_BANK3_PIN11 | /* Pin 91, EMI_D11 */ + HW_PINCTRL_MUXSEL6_BANK3_PIN10 | /* Pin 89, EMI_D10 */ + HW_PINCTRL_MUXSEL6_BANK3_PIN09 | /* Pin 87, EMI_D09 */ + HW_PINCTRL_MUXSEL6_BANK3_PIN08 | /* Pin 86, EMI_D08 */ + HW_PINCTRL_MUXSEL6_BANK3_PIN07 | /* Pin 85, EMI_D07 */ + HW_PINCTRL_MUXSEL6_BANK3_PIN06 | /* Pin 84, EMI_D06 */ + HW_PINCTRL_MUXSEL6_BANK3_PIN05 | /* Pin 83, EMI_D05 */ + HW_PINCTRL_MUXSEL6_BANK3_PIN04 | /* Pin 82, EMI_D04 */ + HW_PINCTRL_MUXSEL6_BANK3_PIN03 | /* Pin 79, EMI_D03 */ + HW_PINCTRL_MUXSEL6_BANK3_PIN02 | /* Pin 77, EMI_D02 */ + HW_PINCTRL_MUXSEL6_BANK3_PIN01 | /* Pin 76, EMI_D01 */ + HW_PINCTRL_MUXSEL6_BANK3_PIN00) /* Pin 75, EMI_D00 */ + ); + + REG_WRITE(HW_PINCTRL_BASE + HW_PINCTRL_MUXSEL7_CLR, ( + HW_PINCTRL_MUXSEL7_BANK3_PIN21 | /* Pin 72, EMI_CLKN */ + HW_PINCTRL_MUXSEL7_BANK3_PIN20 | /* Pin 70, EMI_CLK */ + HW_PINCTRL_MUXSEL7_BANK3_PIN19 | /* Pin 74, EMI_DQS1 */ + HW_PINCTRL_MUXSEL7_BANK3_PIN18 | /* Pin 73, EMI_DQS0 */ + HW_PINCTRL_MUXSEL7_BANK3_PIN17 | /* Pin 92, EMI_DQM1 */ + HW_PINCTRL_MUXSEL7_BANK3_PIN16) /* Pin 81, EMI_DQM0 */ + ); + + return; +} + +/* + * Configure EMI pins voltages to 1.8/2.5V operation and drive strength + * to "ma". + */ +void +configure_emi_drive(int ma) +{ + uint32_t drive; + + /* DRIVE 9 */ + drive = REG_READ(HW_PINCTRL_BASE + HW_PINCTRL_DRIVE9); + drive &= ~( + HW_PINCTRL_DRIVE9_BANK2_PIN15_V | /* Pin 108, EMI_A06 */ + HW_PINCTRL_DRIVE9_BANK2_PIN15_MA | + HW_PINCTRL_DRIVE9_BANK2_PIN14_V | /* Pin 107, EMI_A05 */ + HW_PINCTRL_DRIVE9_BANK2_PIN14_MA | + HW_PINCTRL_DRIVE9_BANK2_PIN13_V | /* Pin 109, EMI_A04 */ + HW_PINCTRL_DRIVE9_BANK2_PIN13_MA | + HW_PINCTRL_DRIVE9_BANK2_PIN12_V | /* Pin 110, EMI_A03 */ + HW_PINCTRL_DRIVE9_BANK2_PIN12_MA | + HW_PINCTRL_DRIVE9_BANK2_PIN11_V | /* Pin 111, EMI_A02 */ + HW_PINCTRL_DRIVE9_BANK2_PIN11_MA | + HW_PINCTRL_DRIVE9_BANK2_PIN10_V | /* Pin 112, EMI_A01 */ + HW_PINCTRL_DRIVE9_BANK2_PIN10_MA | + HW_PINCTRL_DRIVE9_BANK2_PIN09_V | /* Pin 113, EMI_A00 */ + HW_PINCTRL_DRIVE9_BANK2_PIN09_MA | + HW_PINCTRL_DRIVE9_RSRVD6 | /* Always write zeroes */ + HW_PINCTRL_DRIVE9_RSRVD5 | + HW_PINCTRL_DRIVE9_RSRVD4 | + HW_PINCTRL_DRIVE9_RSRVD3 | + HW_PINCTRL_DRIVE9_RSRVD2 | + HW_PINCTRL_DRIVE9_RSRVD1 | + HW_PINCTRL_DRIVE9_RSRVD0 + ); + drive |= ( + __SHIFTIN(ma, HW_PINCTRL_DRIVE9_BANK2_PIN15_MA) | /* EMI_A06 */ + __SHIFTIN(ma, HW_PINCTRL_DRIVE9_BANK2_PIN14_MA) | /* EMI_A05 */ + __SHIFTIN(ma, HW_PINCTRL_DRIVE9_BANK2_PIN13_MA) | /* EMI_A04 */ + __SHIFTIN(ma, HW_PINCTRL_DRIVE9_BANK2_PIN12_MA) | /* EMI_A03 */ + __SHIFTIN(ma, HW_PINCTRL_DRIVE9_BANK2_PIN11_MA) | /* EMI_A02 */ + __SHIFTIN(ma, HW_PINCTRL_DRIVE9_BANK2_PIN10_MA) | /* EMI_A01 */ + __SHIFTIN(ma, HW_PINCTRL_DRIVE9_BANK2_PIN09_MA) /* EMI_A00 */ + ); + REG_WRITE(HW_PINCTRL_BASE + HW_PINCTRL_DRIVE9, drive); + + /* DRIVE 10 */ + drive = REG_READ(HW_PINCTRL_BASE + HW_PINCTRL_DRIVE10); + drive &= ~( + HW_PINCTRL_DRIVE10_BANK2_PIN23_V | /* Pin 117, EMI_BA1 */ + HW_PINCTRL_DRIVE10_BANK2_PIN23_MA | + HW_PINCTRL_DRIVE10_BANK2_PIN22_V | /* Pin 116, EMI_BA0 */ + HW_PINCTRL_DRIVE10_BANK2_PIN22_MA | + HW_PINCTRL_DRIVE10_BANK2_PIN21_V | /* Pin 101, EMI_A12 */ + HW_PINCTRL_DRIVE10_BANK2_PIN21_MA | + HW_PINCTRL_DRIVE10_BANK2_PIN20_V | /* Pin 102, EMI_A11 */ + HW_PINCTRL_DRIVE10_BANK2_PIN20_MA | + HW_PINCTRL_DRIVE10_BANK2_PIN19_V | /* Pin 104, EMI_A10 */ + HW_PINCTRL_DRIVE10_BANK2_PIN19_MA | + HW_PINCTRL_DRIVE10_BANK2_PIN18_V | /* Pin 103, EMI_A09 */ + HW_PINCTRL_DRIVE10_BANK2_PIN18_MA | + HW_PINCTRL_DRIVE10_BANK2_PIN17_V | /* Pin 106, EMI_A08 */ + HW_PINCTRL_DRIVE10_BANK2_PIN17_MA | + HW_PINCTRL_DRIVE10_BANK2_PIN16_V | /* Pin 105, EMI_A07 */ + HW_PINCTRL_DRIVE10_BANK2_PIN16_MA | + HW_PINCTRL_DRIVE10_RSRVD6 | /* Always write zeroes */ + HW_PINCTRL_DRIVE10_RSRVD5 | + HW_PINCTRL_DRIVE10_RSRVD4 | + HW_PINCTRL_DRIVE10_RSRVD3 | + HW_PINCTRL_DRIVE10_RSRVD2 | + HW_PINCTRL_DRIVE10_RSRVD1 | + HW_PINCTRL_DRIVE10_RSRVD0 + ); + drive |= ( + __SHIFTIN(ma, HW_PINCTRL_DRIVE10_BANK2_PIN23_MA) | /* EMI_BA1 */ + __SHIFTIN(ma, HW_PINCTRL_DRIVE10_BANK2_PIN22_MA) | /* EMI_BA0 */ + __SHIFTIN(ma, HW_PINCTRL_DRIVE10_BANK2_PIN21_MA) | /* EMI_A12 */ + __SHIFTIN(ma, HW_PINCTRL_DRIVE10_BANK2_PIN20_MA) | /* EMI_A11 */ + __SHIFTIN(ma, HW_PINCTRL_DRIVE10_BANK2_PIN19_MA) | /* EMI_A10 */ + __SHIFTIN(ma, HW_PINCTRL_DRIVE10_BANK2_PIN18_MA) | /* EMI_A09 */ + __SHIFTIN(ma, HW_PINCTRL_DRIVE10_BANK2_PIN17_MA) | /* EMI_A08 */ + __SHIFTIN(ma, HW_PINCTRL_DRIVE10_BANK2_PIN16_MA) /* EMI_A07 */ + ); + REG_WRITE(HW_PINCTRL_BASE + HW_PINCTRL_DRIVE10, drive); + + /* DRIVE 11 */ + drive = REG_READ(HW_PINCTRL_BASE + HW_PINCTRL_DRIVE11); + drive &= ~( + HW_PINCTRL_DRIVE11_BANK2_PIN31_V | /* Pin 114, EMI_WEN */ + HW_PINCTRL_DRIVE11_BANK2_PIN31_MA | + HW_PINCTRL_DRIVE11_BANK2_PIN30_V | /* Pin 98, EMI_RASN */ + HW_PINCTRL_DRIVE11_BANK2_PIN30_MA | + HW_PINCTRL_DRIVE11_BANK2_PIN29_V | /* Pin 115, EMI_CKE */ + HW_PINCTRL_DRIVE11_BANK2_PIN29_MA | +#if 0 + /* 169-Pin BGA Package */ + HW_PINCTRL_DRIVE11_BANK2_PIN26_V | /* Pin 99, EMI_CE1N */ + HW_PINCTRL_DRIVE11_BANK2_PIN26_MA | +#endif + HW_PINCTRL_DRIVE11_BANK2_PIN25_V | /* Pin 100, EMI_CE0N */ + HW_PINCTRL_DRIVE11_BANK2_PIN25_MA | + HW_PINCTRL_DRIVE11_BANK2_PIN24_V | /* Pin 97, EMI_CASN */ + HW_PINCTRL_DRIVE11_BANK2_PIN24_MA | + HW_PINCTRL_DRIVE11_RSRVD6 | /* Always write zeroes */ + HW_PINCTRL_DRIVE11_RSRVD5 | + HW_PINCTRL_DRIVE11_RSRVD4 | + HW_PINCTRL_DRIVE11_RSRVD3 | + HW_PINCTRL_DRIVE11_RSRVD2 | + HW_PINCTRL_DRIVE11_RSRVD1 | + HW_PINCTRL_DRIVE11_RSRVD0 + ); + drive |= ( + __SHIFTIN(ma, HW_PINCTRL_DRIVE11_BANK2_PIN31_MA) | /* EMI_WEN */ + __SHIFTIN(ma, HW_PINCTRL_DRIVE11_BANK2_PIN30_MA) | /* EMI_RASN */ + __SHIFTIN(ma, HW_PINCTRL_DRIVE11_BANK2_PIN29_MA) | /* EMI_CKE */ +#if 0 /* 169-Pin BGA Package */ + __SHIFTIN(ma, HW_PINCTRL_DRIVE11_BANK2_PIN26_MA) | /* EMI_CE1N */ +#endif + __SHIFTIN(ma, HW_PINCTRL_DRIVE11_BANK2_PIN25_MA) | /* EMI_CE0N */ + __SHIFTIN(ma, HW_PINCTRL_DRIVE11_BANK2_PIN24_MA) /* EMI_CASN */ + ); + REG_WRITE(HW_PINCTRL_BASE + HW_PINCTRL_DRIVE11, drive); + + /* DRIVE 12 */ + drive = REG_READ(HW_PINCTRL_BASE + HW_PINCTRL_DRIVE12); + drive &= ~( + HW_PINCTRL_DRIVE12_BANK3_PIN07_V | /* Pin 85, EMI_D07 */ + HW_PINCTRL_DRIVE12_BANK3_PIN07_MA | + HW_PINCTRL_DRIVE12_BANK3_PIN06_V | /* Pin 84, EMI_D06 */ + HW_PINCTRL_DRIVE12_BANK3_PIN06_MA | + HW_PINCTRL_DRIVE12_BANK3_PIN05_V | /* Pin 83, EMI_D05 */ + HW_PINCTRL_DRIVE12_BANK3_PIN05_MA | + HW_PINCTRL_DRIVE12_BANK3_PIN04_V | /* Pin 82, EMI_D04 */ + HW_PINCTRL_DRIVE12_BANK3_PIN04_MA | + HW_PINCTRL_DRIVE12_BANK3_PIN03_V | /* Pin 79, EMI_D03 */ + HW_PINCTRL_DRIVE12_BANK3_PIN03_MA | + HW_PINCTRL_DRIVE12_BANK3_PIN02_V | /* Pin 77, EMI_D02 */ + HW_PINCTRL_DRIVE12_BANK3_PIN02_MA | + HW_PINCTRL_DRIVE12_BANK3_PIN01_V | /* Pin 76, EMI_D01 */ + HW_PINCTRL_DRIVE12_BANK3_PIN01_MA | + HW_PINCTRL_DRIVE12_BANK3_PIN00_V | /* Pin 75, EMI_D00 */ + HW_PINCTRL_DRIVE12_BANK3_PIN00_MA | + HW_PINCTRL_DRIVE12_RSRVD6 | /* Always write zeroes */ + HW_PINCTRL_DRIVE12_RSRVD5 | + HW_PINCTRL_DRIVE12_RSRVD4 | + HW_PINCTRL_DRIVE12_RSRVD3 | + HW_PINCTRL_DRIVE12_RSRVD2 | + HW_PINCTRL_DRIVE12_RSRVD1 | + HW_PINCTRL_DRIVE12_RSRVD0 + ); + drive |= ( + __SHIFTIN(ma, HW_PINCTRL_DRIVE12_BANK3_PIN07_MA) | /* EMI_D07 */ + __SHIFTIN(ma, HW_PINCTRL_DRIVE12_BANK3_PIN06_MA) | /* EMI_D06 */ + __SHIFTIN(ma, HW_PINCTRL_DRIVE12_BANK3_PIN05_MA) | /* EMI_D05 */ + __SHIFTIN(ma, HW_PINCTRL_DRIVE12_BANK3_PIN04_MA) | /* EMI_D04 */ + __SHIFTIN(ma, HW_PINCTRL_DRIVE12_BANK3_PIN03_MA) | /* EMI_D03 */ + __SHIFTIN(ma, HW_PINCTRL_DRIVE12_BANK3_PIN02_MA) | /* EMI_D02 */ + __SHIFTIN(ma, HW_PINCTRL_DRIVE12_BANK3_PIN01_MA) | /* EMI_D01 */ + __SHIFTIN(ma, HW_PINCTRL_DRIVE12_BANK3_PIN00_MA) /* EMI_D00 */ + ); + REG_WRITE(HW_PINCTRL_BASE + HW_PINCTRL_DRIVE12, drive); + + /* DRIVE 13 */ + drive = REG_READ(HW_PINCTRL_BASE + HW_PINCTRL_DRIVE13); + drive &= ~( + HW_PINCTRL_DRIVE13_BANK3_PIN15_V | /* Pin 95, EMI_D15 */ + HW_PINCTRL_DRIVE13_BANK3_PIN15_MA | + HW_PINCTRL_DRIVE13_BANK3_PIN14_V | /* Pin 96, EMI_D14 */ + HW_PINCTRL_DRIVE13_BANK3_PIN14_MA | + HW_PINCTRL_DRIVE13_BANK3_PIN13_V | /* Pin 94, EMI_D13 */ + HW_PINCTRL_DRIVE13_BANK3_PIN13_MA | + HW_PINCTRL_DRIVE13_BANK3_PIN12_V | /* Pin 93, EMI_D12 */ + HW_PINCTRL_DRIVE13_BANK3_PIN12_MA | + HW_PINCTRL_DRIVE13_BANK3_PIN11_V | /* Pin 91, EMI_D11 */ + HW_PINCTRL_DRIVE13_BANK3_PIN11_MA | + HW_PINCTRL_DRIVE13_BANK3_PIN10_V | /* Pin 89, EMI_D10 */ + HW_PINCTRL_DRIVE13_BANK3_PIN10_MA | + HW_PINCTRL_DRIVE13_BANK3_PIN09_V | /* Pin 87, EMI_D09 */ + HW_PINCTRL_DRIVE13_BANK3_PIN09_MA | + HW_PINCTRL_DRIVE13_BANK3_PIN08_V | /* Pin 86, EMI_D08 */ + HW_PINCTRL_DRIVE13_BANK3_PIN08_MA | + HW_PINCTRL_DRIVE13_RSRVD6 | /* Always write zeroes */ + HW_PINCTRL_DRIVE13_RSRVD5 | + HW_PINCTRL_DRIVE13_RSRVD4 | + HW_PINCTRL_DRIVE13_RSRVD3 | + HW_PINCTRL_DRIVE13_RSRVD2 | + HW_PINCTRL_DRIVE13_RSRVD1 | + HW_PINCTRL_DRIVE13_RSRVD0 + ); + drive |= ( + __SHIFTIN(ma, HW_PINCTRL_DRIVE13_BANK3_PIN15_MA) | /* EMI_D15 */ + __SHIFTIN(ma, HW_PINCTRL_DRIVE13_BANK3_PIN14_MA) | /* EMI_D14 */ + __SHIFTIN(ma, HW_PINCTRL_DRIVE13_BANK3_PIN13_MA) | /* EMI_D13 */ + __SHIFTIN(ma, HW_PINCTRL_DRIVE13_BANK3_PIN12_MA) | /* EMI_D12 */ + __SHIFTIN(ma, HW_PINCTRL_DRIVE13_BANK3_PIN11_MA) | /* EMI_D11 */ + __SHIFTIN(ma, HW_PINCTRL_DRIVE13_BANK3_PIN10_MA) | /* EMI_D10 */ + __SHIFTIN(ma, HW_PINCTRL_DRIVE13_BANK3_PIN09_MA) | /* EMI_D09 */ + __SHIFTIN(ma, HW_PINCTRL_DRIVE13_BANK3_PIN08_MA) /* EMI_D08 */ + ); + REG_WRITE(HW_PINCTRL_BASE + HW_PINCTRL_DRIVE13, drive); + + /* DRIVE 14 */ + drive = REG_READ(HW_PINCTRL_BASE + HW_PINCTRL_DRIVE14); + drive &= ~( + HW_PINCTRL_DRIVE14_BANK3_PIN21_V | /* Pin 72, EMI_CLKN */ + HW_PINCTRL_DRIVE14_BANK3_PIN21_MA | + HW_PINCTRL_DRIVE14_BANK3_PIN20_V | /* Pin 70, EMI_CLK */ + HW_PINCTRL_DRIVE14_BANK3_PIN20_MA | + HW_PINCTRL_DRIVE14_BANK3_PIN19_V | /* Pin 74, EMI_DQS1 */ + HW_PINCTRL_DRIVE14_BANK3_PIN19_MA | + HW_PINCTRL_DRIVE14_BANK3_PIN18_V | /* Pin 73, EMI_DQS0 */ + HW_PINCTRL_DRIVE14_BANK3_PIN18_MA | + HW_PINCTRL_DRIVE14_BANK3_PIN17_V | /* Pin 92, EMI_DQM1 */ + HW_PINCTRL_DRIVE14_BANK3_PIN17_MA | + HW_PINCTRL_DRIVE14_BANK3_PIN16_V | /* Pin 81, EMI_DQM0 */ + HW_PINCTRL_DRIVE14_BANK3_PIN16_MA | + HW_PINCTRL_DRIVE14_RSRVD6 | /* Always write zeroes */ + HW_PINCTRL_DRIVE14_RSRVD5 | + HW_PINCTRL_DRIVE14_RSRVD4 | + HW_PINCTRL_DRIVE14_RSRVD3 | + HW_PINCTRL_DRIVE14_RSRVD2 | + HW_PINCTRL_DRIVE14_RSRVD1 | + HW_PINCTRL_DRIVE14_RSRVD0 + ); + drive |= ( + __SHIFTIN(ma, HW_PINCTRL_DRIVE14_BANK3_PIN21_MA) | /* EMI_CLKN */ + __SHIFTIN(ma, HW_PINCTRL_DRIVE14_BANK3_PIN20_MA) | /* EMI_CLK */ + __SHIFTIN(ma, HW_PINCTRL_DRIVE14_BANK3_PIN19_MA) | /* EMI_DQS1 */ + __SHIFTIN(ma, HW_PINCTRL_DRIVE14_BANK3_PIN18_MA) | /* EMI_DQS0 */ + __SHIFTIN(ma, HW_PINCTRL_DRIVE14_BANK3_PIN17_MA) | /* EMI_DQM1 */ + __SHIFTIN(ma, HW_PINCTRL_DRIVE14_BANK3_PIN16_MA) /* EMI_DQM0 */ + ); + REG_WRITE(HW_PINCTRL_BASE + HW_PINCTRL_DRIVE14, drive); + + return; +} + +/* + * Disable internal gate keepers on EMI pins. + */ +void +disable_emi_padkeepers(void) +{ + + REG_WRITE(HW_PINCTRL_BASE + HW_PINCTRL_PULL3_SET, ( + HW_PINCTRL_PULL3_BANK3_PIN17 | /* EMI_DQM1 */ + HW_PINCTRL_PULL3_BANK3_PIN16 | /* EMI_DQM0 */ + HW_PINCTRL_PULL3_BANK3_PIN15 | /* EMI_D15 */ + HW_PINCTRL_PULL3_BANK3_PIN14 | /* EMI_D14 */ + HW_PINCTRL_PULL3_BANK3_PIN13 | /* EMI_D13 */ + HW_PINCTRL_PULL3_BANK3_PIN12 | /* EMI_D12 */ + HW_PINCTRL_PULL3_BANK3_PIN11 | /* EMI_D11 */ + HW_PINCTRL_PULL3_BANK3_PIN10 | /* EMI_D10 */ + HW_PINCTRL_PULL3_BANK3_PIN09 | /* EMI_D09 */ + HW_PINCTRL_PULL3_BANK3_PIN08 | /* EMI_D08 */ + HW_PINCTRL_PULL3_BANK3_PIN07 | /* EMI_D07 */ + HW_PINCTRL_PULL3_BANK3_PIN06 | /* EMI_D06 */ + HW_PINCTRL_PULL3_BANK3_PIN05 | /* EMI_D05 */ + HW_PINCTRL_PULL3_BANK3_PIN04 | /* EMI_D04 */ + HW_PINCTRL_PULL3_BANK3_PIN03 | /* EMI_D03 */ + HW_PINCTRL_PULL3_BANK3_PIN02 | /* EMI_D02 */ + HW_PINCTRL_PULL3_BANK3_PIN01 | /* EMI_D01 */ + HW_PINCTRL_PULL3_BANK3_PIN00) /* EMI_D00 */ + ); + + return; +} + +/* + * Configure external SSP pins to be used for SD/MMC. + */ +void +configure_ssp_mux(void) +{ + REG_WRITE(HW_PINCTRL_BASE + HW_PINCTRL_MUXSEL4_CLR, ( + HW_PINCTRL_MUXSEL4_BANK2_PIN00 | /* Pin 121, SSP1_CMD */ + HW_PINCTRL_MUXSEL4_BANK2_PIN02 | /* Pin 122, SSP1_DATA0 */ + HW_PINCTRL_MUXSEL4_BANK2_PIN03 | /* Pin 123, SSP1_DATA1 */ + HW_PINCTRL_MUXSEL4_BANK2_PIN04 | /* Pin 124, SSP1_DATA2 */ + HW_PINCTRL_MUXSEL4_BANK2_PIN05 | /* Pin 125, SSP1_DATA3 */ + HW_PINCTRL_MUXSEL4_BANK2_PIN06) /* Pin 127, SSP1_SCK */ + ); + + return; +} + +/* + * Configure SSP pins drive strength to "ma". + * Out of reset, all non-EMI pins are configured as 3.3 V. + */ +void +configure_ssp_drive(int ma) +{ + uint32_t reg = REG_READ(HW_PINCTRL_BASE + HW_PINCTRL_DRIVE8); + reg &= ~( + HW_PINCTRL_DRIVE8_BANK2_PIN06_MA | /* Pin 127, SSP1_SCK */ + HW_PINCTRL_DRIVE8_BANK2_PIN05_MA | /* Pin 125, SSP1_DATA3 */ + HW_PINCTRL_DRIVE8_BANK2_PIN04_MA | /* Pin 124, SSP1_DATA2 */ + HW_PINCTRL_DRIVE8_BANK2_PIN03_MA | /* Pin 123, SSP1_DATA1 */ + HW_PINCTRL_DRIVE8_BANK2_PIN02_MA | /* Pin 122, SSP1_DATA0 */ + HW_PINCTRL_DRIVE8_BANK2_PIN00_MA /* Pin 121, SSP1_CMD */ + ); + + reg |= __SHIFTIN(ma, HW_PINCTRL_DRIVE8_BANK2_PIN06_MA) | + __SHIFTIN(ma, HW_PINCTRL_DRIVE8_BANK2_PIN05_MA) | + __SHIFTIN(ma, HW_PINCTRL_DRIVE8_BANK2_PIN04_MA) | + __SHIFTIN(ma, HW_PINCTRL_DRIVE8_BANK2_PIN03_MA) | + __SHIFTIN(ma, HW_PINCTRL_DRIVE8_BANK2_PIN02_MA) | + __SHIFTIN(ma, HW_PINCTRL_DRIVE8_BANK2_PIN00_MA + ); + + REG_WRITE(HW_PINCTRL_BASE + HW_PINCTRL_DRIVE8, reg); + + return; +} + +/* + * Configure SSP pull ups. + */ +void +configure_ssp_pullups(void) +{ + /* Disable pull ups for SSP and let HW take care of them. */ +// REG_WRITE(HW_PINCTRL_BASE + HW_PINCTRL_PULL2_CLR, ( +// HW_PINCTRL_PULL2_BANK2_PIN05 |/* Pin 125, SSP1_DATA3 */ +// HW_PINCTRL_PULL2_BANK2_PIN04 | /* Pin 124, SSP1_DATA2 */ +// HW_PINCTRL_PULL2_BANK2_PIN03 | /* Pin 123, SSP1_DATA1 */ +// HW_PINCTRL_PULL2_BANK2_PIN02 | /* Pin 122, SSP1_DATA0 */ +// HW_PINCTRL_PULL2_BANK2_PIN00 /* Pin 121, SSP1_CMD */ +// )); + + REG_WRITE(HW_PINCTRL_BASE + HW_PINCTRL_PULL2_SET, ( + HW_PINCTRL_PULL2_BANK2_PIN05 |/* Pin 125, SSP1_DATA3 */ + HW_PINCTRL_PULL2_BANK2_PIN04 | /* Pin 124, SSP1_DATA2 */ + HW_PINCTRL_PULL2_BANK2_PIN03 | /* Pin 123, SSP1_DATA1 */ + HW_PINCTRL_PULL2_BANK2_PIN02 | /* Pin 122, SSP1_DATA0 */ + HW_PINCTRL_PULL2_BANK2_PIN00 /* Pin 121, SSP1_CMD */ + )); + + return; +} diff --git a/sys/arch/evbarm/stand/bootimx23/power_prep.c b/sys/arch/evbarm/stand/bootimx23/power_prep.c new file mode 100644 index 000000000000..cc268d272b6c --- /dev/null +++ b/sys/arch/evbarm/stand/bootimx23/power_prep.c @@ -0,0 +1,579 @@ +/* $Id: power_prep.c,v 1.1 2012/11/20 19:08:46 jkunz Exp $ */ + +/* + * Copyright (c) 2012 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Petri Laakso. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include + +#include + +#include + +#include "common.h" + +void charge_4p2_capacitance(void); +void enable_4p2_linreg(void); +void enable_dcdc(void); +void enable_vbusvalid_comparator(void); +void set_targets(void); +void dcdc4p2_enable_dcdc(void); +void p5vctrl_enable_dcdc(void); +void enable_vddmem(void); + +/* + * Power rail voltage targets, brownout levels and linear regulator + * offsets from the target. + * + * Supply Target BO LinReg offset + * ------------------------------------------ + * VDDD 1.550 V 1.450 V -25 mV + * VDDA 1.750 V 1.575 V -25 mV + * VDDIO 3.100 V 2.925 V -25 mV + * VDDMEM 2.500 V + * + * BO = Brownout level below target. + */ +#define VDDD_TARGET 0x1e +#define VDDD_BO_OFFSET 0x4 +#define VDDD_LINREG_OFFSET 0x02 + +#define VDDA_TARGET 0x0A +#define VDDA_BO_OFFSET 0x07 +#define VDDA_LINREG_OFFSET 0x02 + +#define VDDIO_TARGET 0x0C +#define VDDIO_BO_OFFSET 0x07 +#define VDDIO_LINREG_OFFSET 0x02 + +#define VDDMEM_TARGET 0x10 + +/* + * Threshold voltage for the VBUSVALID comparator. + * Always make sure that the VDD5V voltage level is higher. + */ +#define VBUSVALID_TRSH 0x02 /* 4.1 V */ + +/* Limits for BATT charger + 4P2 current */ +#define P4P2_ILIMIT_MIN 0x01 /* 10 mA */ +#define P4P2_ILIMIT_MAX 0x3f /* 780 mA */ + +/* + * Trip point for the comparison between the DCDC_4P2 and BATTERY pin. + * If this voltage comparation is true then 5 V originated power will supply + * the DCDC. Otherwise battery will be used. + */ +#define DCDC4P2_CMPTRIP 0x00 /* DCDC_4P2 pin > 0.85 * BATTERY pin */ + +/* + * Adjust the behavior of the DCDC and 4.2 V circuit. + * Two MSBs control the VDD4P2 brownout below the DCDC4P2_TRG before the + * regulation circuit steals battery charge. Two LSBs control which power + * source is selected by the DCDC. + */ +#define DCDC4P2_DROPOUT_CTRL_BO_200 0x0C +#define DCDC4P2_DROPOUT_CTRL_BO_100 0x08 +#define DCDC4P2_DROPOUT_CTRL_BO_050 0x04 +#define DCDC4P2_DROPOUT_CTRL_BO_025 0x00 + +#define DCDC4P2_DROPOUT_CTRL_SEL_4P2 0x00 /* Don't use battery at all. */ +#define DCDC4P2_DROPOUT_CTRL_SEL_BATT_IF_GT_4P2 0x01 /* BATT if 4P2 < BATT */ +#define DCDC4P2_DROPOUT_CTRL_SEL_HIGHER 0x02 /* Selects which ever is + * higher. */ + +#define DCDC4P2_DROPOUT_CTRL (DCDC4P2_DROPOUT_CTRL_BO_200 |\ + DCDC4P2_DROPOUT_CTRL_SEL_4P2) + +/* + * Prepare system for a 5 V operation. + * + * The system uses inefficient linear regulators as a power source after boot. + * This code enables the use of more energy efficient DC-DC converter as a + * power source. + */ +int +power_prep(void) +{ + + /* Enable clocks to the power block */ + REG_WRITE(HW_POWER_BASE + HW_POWER_CTRL_CLR, HW_POWER_CTRL_CLKGATE); + + set_targets(); + enable_vbusvalid_comparator(); + enable_4p2_linreg(); + charge_4p2_capacitance(); + enable_dcdc(); + enable_vddmem(); + + return 0; +} + +/* + * Set switching converter voltage targets, brownout levels and linear + * regulator output offsets. + */ +void +set_targets(void) +{ + uint32_t vddctrl; + + /* VDDD */ + vddctrl = REG_READ(HW_POWER_BASE + HW_POWER_VDDDCTRL); + + vddctrl &= ~(HW_POWER_VDDDCTRL_LINREG_OFFSET | + HW_POWER_VDDDCTRL_BO_OFFSET | + HW_POWER_VDDDCTRL_TRG); + vddctrl |= + __SHIFTIN(VDDD_LINREG_OFFSET, HW_POWER_VDDDCTRL_LINREG_OFFSET) | + __SHIFTIN(VDDD_BO_OFFSET, HW_POWER_VDDDCTRL_BO_OFFSET) | + __SHIFTIN(VDDD_TARGET, HW_POWER_VDDDCTRL_TRG); + + REG_WRITE(HW_POWER_BASE + HW_POWER_VDDDCTRL, vddctrl); + + /* VDDA */ + vddctrl = REG_READ(HW_POWER_BASE + HW_POWER_VDDACTRL); + + vddctrl &= ~(HW_POWER_VDDACTRL_LINREG_OFFSET | + HW_POWER_VDDACTRL_BO_OFFSET | + HW_POWER_VDDACTRL_TRG); + vddctrl |= + __SHIFTIN(VDDA_LINREG_OFFSET, HW_POWER_VDDACTRL_LINREG_OFFSET) | + __SHIFTIN(VDDA_BO_OFFSET, HW_POWER_VDDACTRL_BO_OFFSET) | + __SHIFTIN(VDDA_TARGET, HW_POWER_VDDACTRL_TRG); + + REG_WRITE(HW_POWER_BASE + HW_POWER_VDDACTRL, vddctrl); + + /* VDDIO */ + vddctrl = REG_READ(HW_POWER_BASE + HW_POWER_VDDIOCTRL); + + vddctrl &= ~(HW_POWER_VDDIOCTRL_LINREG_OFFSET | + HW_POWER_VDDIOCTRL_BO_OFFSET | + HW_POWER_VDDIOCTRL_TRG); + vddctrl |= + __SHIFTIN(VDDIO_LINREG_OFFSET, HW_POWER_VDDACTRL_LINREG_OFFSET) | + __SHIFTIN(VDDIO_BO_OFFSET, HW_POWER_VDDACTRL_BO_OFFSET) | + __SHIFTIN(VDDIO_TARGET, HW_POWER_VDDACTRL_TRG); + + REG_WRITE(HW_POWER_BASE + HW_POWER_VDDIOCTRL, vddctrl); + + /* VDDMEM */ + vddctrl = REG_READ(HW_POWER_BASE + HW_POWER_VDDMEMCTRL); + vddctrl &= ~(HW_POWER_VDDMEMCTRL_TRG); + vddctrl |= __SHIFTIN(VDDMEM_TARGET, HW_POWER_VDDMEMCTRL_TRG); + + REG_WRITE(HW_POWER_BASE + HW_POWER_VDDMEMCTRL, vddctrl); + + return; +} + +/* + * VBUSVALID comparator is accurate method to determine the presence of 5 V. + * Turn on the comparator, set its voltage treshold and instruct DC-DC to + * use it. + */ +void +enable_vbusvalid_comparator() +{ + uint32_t p5vctrl; + + /* + * Disable 5 V brownout detection temporarily because setting + * VBUSVALID_5VDETECT can cause false brownout. + */ + REG_WRITE(HW_POWER_BASE + HW_POWER_5VCTRL_CLR, + HW_POWER_5VCTRL_PWDN_5VBRNOUT); + + p5vctrl = REG_READ(HW_POWER_BASE + HW_POWER_5VCTRL); + + p5vctrl &= ~HW_POWER_5VCTRL_VBUSVALID_TRSH; + p5vctrl |= + /* Turn on VBUS comparators. */ + (HW_POWER_5VCTRL_PWRUP_VBUS_CMPS | + /* Set treshold for VBUSVALID comparator. */ + __SHIFTIN(VBUSVALID_TRSH, HW_POWER_5VCTRL_VBUSVALID_TRSH) | + /* Set DC-DC to use VBUSVALID comparator. */ + HW_POWER_5VCTRL_VBUSVALID_5VDETECT); + + REG_WRITE(HW_POWER_BASE + HW_POWER_5VCTRL, p5vctrl); + + /* Enable temporarily disabled 5 V brownout detection. */ + REG_WRITE(HW_POWER_BASE + HW_POWER_5VCTRL_SET, + HW_POWER_5VCTRL_PWDN_5VBRNOUT); + + return; +} + +/* + * Enable 4P2 linear regulator. + */ +void +enable_4p2_linreg(void) +{ + uint32_t dcdc4p2; + uint32_t p5vctrl; + + dcdc4p2 = REG_READ(HW_POWER_BASE + HW_POWER_DCDC4P2); + /* Set the 4P2 target to 4.2 V and BO to 3.6V by clearing TRG and BO + * field. */ + dcdc4p2 &= ~(HW_POWER_DCDC4P2_TRG | HW_POWER_DCDC4P2_BO); + /* Enable the 4P2 circuitry to control the LinReg. */ + dcdc4p2 |= HW_POWER_DCDC4P2_ENABLE_4P2; + REG_WRITE(HW_POWER_BASE + HW_POWER_DCDC4P2, dcdc4p2); + + /* The 4P2 LinReg needs a static load to operate correctly. Since the + * DC-DC is not yet loading the LinReg, another load must be used. */ + REG_WRITE(HW_POWER_BASE + HW_POWER_CHARGE_SET, + HW_POWER_CHARGE_ENABLE_LOAD); + + p5vctrl = REG_READ(HW_POWER_BASE + HW_POWER_5VCTRL); + p5vctrl &= ~(HW_POWER_5VCTRL_CHARGE_4P2_ILIMIT | + /* Power on the 4P2 LinReg. ON = 0x0, OFF = 0x1 */ + HW_POWER_5VCTRL_PWD_CHARGE_4P2); + p5vctrl |= + /* Provide an initial current limit for the 4P2 LinReg with the + * smallest value possible. */ + __SHIFTIN(P4P2_ILIMIT_MIN, HW_POWER_5VCTRL_CHARGE_4P2_ILIMIT); + REG_WRITE(HW_POWER_BASE + HW_POWER_5VCTRL, p5vctrl); + + /* Ungate the path from 4P2 LinReg to DC-DC. */ + dcdc4p2_enable_dcdc(); + + return; +} + +/* + * There is capacitor on the 4P2 output which must be charged before powering + * on the 4P2 linear regulator to avoid brownouts on the 5 V source. + * Charging is done by slowly increasing current limit until it reaches + * P4P2_ILIMIT_MAX. + */ +void +charge_4p2_capacitance(void) +{ + uint32_t ilimit; + uint32_t p5vctrl; + + p5vctrl = REG_READ(HW_POWER_BASE + HW_POWER_5VCTRL); + ilimit = __SHIFTOUT(p5vctrl, HW_POWER_5VCTRL_CHARGE_4P2_ILIMIT); + + /* Increment current limit slowly. */ + while (ilimit < P4P2_ILIMIT_MAX) { + ilimit++; + p5vctrl &= ~(HW_POWER_5VCTRL_CHARGE_4P2_ILIMIT); + p5vctrl |= __SHIFTIN(ilimit, HW_POWER_5VCTRL_CHARGE_4P2_ILIMIT); + REG_WRITE(HW_POWER_BASE + HW_POWER_5VCTRL, p5vctrl); + delay_us(10000); + } + + return; +} + +/* + * Enable DCDC to use 4P2 regulator and set its power source selection logic. + */ +void +enable_dcdc(void) +{ + uint32_t dcdc4p2; + uint32_t vddctrl; + + dcdc4p2 = REG_READ(HW_POWER_BASE + HW_POWER_DCDC4P2); + dcdc4p2 &= ~(HW_POWER_DCDC4P2_CMPTRIP | HW_POWER_DCDC4P2_DROPOUT_CTRL); + /* Comparison between the DCDC_4P2 pin and BATTERY pin to choose which + * will supply the DCDC. */ + dcdc4p2 |= __SHIFTIN(DCDC4P2_CMPTRIP, HW_POWER_DCDC4P2_CMPTRIP); + /* DC-DC brownout and select logic. */ + dcdc4p2 |= __SHIFTIN(DCDC4P2_DROPOUT_CTRL, + HW_POWER_DCDC4P2_DROPOUT_CTRL); + REG_WRITE(HW_POWER_BASE + HW_POWER_DCDC4P2, dcdc4p2); + + /* Disable the automatic DC-DC startup when 5 V is lost (it is on + * already) */ + REG_WRITE(HW_POWER_BASE + HW_POWER_5VCTRL_CLR, + HW_POWER_5VCTRL_DCDC_XFER); + + p5vctrl_enable_dcdc(); + + /* Enable switching converter outputs and disable linear regulators + * for VDDD, VDDIO and VDDA. */ + vddctrl = REG_READ(HW_POWER_BASE + HW_POWER_VDDDCTRL); + vddctrl &= ~(HW_POWER_VDDDCTRL_DISABLE_FET | + HW_POWER_VDDDCTRL_ENABLE_LINREG); + REG_WRITE(HW_POWER_BASE + HW_POWER_VDDDCTRL, vddctrl); + + vddctrl = REG_READ(HW_POWER_BASE + HW_POWER_VDDIOCTRL); + vddctrl &= ~HW_POWER_VDDIOCTRL_DISABLE_FET; + REG_WRITE(HW_POWER_BASE + HW_POWER_VDDIOCTRL, vddctrl); + + vddctrl = REG_READ(HW_POWER_BASE + HW_POWER_VDDACTRL); + vddctrl &= ~(HW_POWER_VDDACTRL_DISABLE_FET | + HW_POWER_VDDACTRL_ENABLE_LINREG); + REG_WRITE(HW_POWER_BASE + HW_POWER_VDDACTRL, vddctrl); + + /* The 4P2 LinReg needs a static load to operate correctly. Since the + * DC-DC is already running we can remove extra 100 ohm load enabled + * before. */ + REG_WRITE(HW_POWER_BASE + HW_POWER_CHARGE_CLR, + HW_POWER_CHARGE_ENABLE_LOAD); + + return; +} + +/* + * DCDC4P2 DCDC enable sequence according to errata #5837 + */ +void +dcdc4p2_enable_dcdc(void) +{ + uint32_t dcdc4p2; + uint32_t p5vctrl; + uint32_t p5vctrl_saved; + uint32_t pctrl; + uint32_t pctrl_saved; + + pctrl_saved = REG_READ(HW_POWER_BASE + HW_POWER_CTRL); + p5vctrl_saved = REG_READ(HW_POWER_BASE + HW_POWER_5VCTRL); + + /* Disable the power rail brownout interrupts. */ + REG_WRITE(HW_POWER_BASE + HW_POWER_CTRL_CLR, + (HW_POWER_CTRL_ENIRQ_VDDA_BO | + HW_POWER_CTRL_ENIRQ_VDDD_BO | + HW_POWER_CTRL_ENIRQ_VDDIO_BO)); + + /* Set the HW_POWER_5VCTRL PWRUP_VBUS_CMPS bit (may already be set) */ + REG_WRITE(HW_POWER_BASE + HW_POWER_5VCTRL_SET, + HW_POWER_5VCTRL_PWRUP_VBUS_CMPS); + + /* Set the HW_POWER_5VCTRL VBUSVALID_5VDETECT bit to 0 */ + REG_WRITE(HW_POWER_BASE + HW_POWER_5VCTRL_CLR, + HW_POWER_5VCTRL_VBUSVALID_5VDETECT); + + /* Set the HW_POWER_5VCTRL VBUSVALID_TRSH to 0x0 (2.9 V) */ + REG_WRITE(HW_POWER_BASE + HW_POWER_5VCTRL_CLR, + HW_POWER_5VCTRL_VBUSVALID_TRSH); + + /* Disable VBUSDROOP status and interrupt. */ + REG_WRITE(HW_POWER_BASE + HW_POWER_CTRL_CLR, + (HW_POWER_CTRL_VDD5V_DROOP_IRQ | HW_POWER_CTRL_ENIRQ_VDD5V_DROOP)); + + /* Set the ENABLE_DCDC bit in HW_POWER_DCDC4P2. */ + dcdc4p2 = REG_READ(HW_POWER_BASE + HW_POWER_DCDC4P2); + dcdc4p2 |= HW_POWER_DCDC4P2_ENABLE_DCDC; + REG_WRITE(HW_POWER_BASE + HW_POWER_DCDC4P2, dcdc4p2); + + delay_us(100); + + pctrl = REG_READ(HW_POWER_BASE + HW_POWER_CTRL); + /* VBUSVALID_IRQ is set. */ + if (__SHIFTOUT(pctrl, HW_POWER_CTRL_VBUSVALID_IRQ)) { + /* Set and clear the PWD_CHARGE_4P2 bit to repower on the 4P2 + * regulator because it is automatically shut off on a + * VBUSVALID false condition. */ + REG_WRITE(HW_POWER_BASE + HW_POWER_5VCTRL_SET, + HW_POWER_5VCTRL_PWD_CHARGE_4P2); + REG_WRITE(HW_POWER_BASE + HW_POWER_5VCTRL_CLR, + HW_POWER_5VCTRL_PWD_CHARGE_4P2); + /* Ramp up the CHARGE_4P2_ILIMIT value at this point. */ + charge_4p2_capacitance(); + } + + /* Restore modified bits back to HW_POWER_CTRL. */ + if (pctrl_saved & HW_POWER_CTRL_ENIRQ_VDDA_BO) + REG_WRITE(HW_POWER_BASE + HW_POWER_CTRL_SET, + HW_POWER_CTRL_ENIRQ_VDDA_BO); + else + REG_WRITE(HW_POWER_BASE + HW_POWER_CTRL_CLR, + HW_POWER_CTRL_ENIRQ_VDDA_BO); + + if (pctrl_saved & HW_POWER_CTRL_ENIRQ_VDDD_BO) + REG_WRITE(HW_POWER_BASE + HW_POWER_CTRL_SET, + HW_POWER_CTRL_ENIRQ_VDDD_BO); + else + REG_WRITE(HW_POWER_BASE + HW_POWER_CTRL_CLR, + HW_POWER_CTRL_ENIRQ_VDDD_BO); + + if (pctrl_saved & HW_POWER_CTRL_ENIRQ_VDDIO_BO) + REG_WRITE(HW_POWER_BASE + HW_POWER_CTRL_SET, + HW_POWER_CTRL_ENIRQ_VDDIO_BO); + else + REG_WRITE(HW_POWER_BASE + HW_POWER_CTRL_CLR, + HW_POWER_CTRL_ENIRQ_VDDIO_BO); + + if (pctrl_saved & HW_POWER_CTRL_VDD5V_DROOP_IRQ) + REG_WRITE(HW_POWER_BASE + HW_POWER_CTRL_SET, + HW_POWER_CTRL_VDD5V_DROOP_IRQ); + else + REG_WRITE(HW_POWER_BASE + HW_POWER_CTRL_CLR, + HW_POWER_CTRL_VDD5V_DROOP_IRQ); + + if (pctrl_saved & HW_POWER_CTRL_ENIRQ_VDD5V_DROOP) + REG_WRITE(HW_POWER_BASE + HW_POWER_CTRL_SET, + HW_POWER_CTRL_ENIRQ_VDD5V_DROOP); + else + REG_WRITE(HW_POWER_BASE + HW_POWER_CTRL_CLR, + HW_POWER_CTRL_ENIRQ_VDD5V_DROOP); + + /* Restore modified bits back to HW_POWER_5VCTRL. */ + p5vctrl = REG_READ(HW_POWER_BASE + HW_POWER_5VCTRL); + p5vctrl &= ~(HW_POWER_5VCTRL_PWRUP_VBUS_CMPS | + HW_POWER_5VCTRL_VBUSVALID_5VDETECT | + HW_POWER_5VCTRL_VBUSVALID_TRSH); + p5vctrl |= __SHIFTOUT(p5vctrl_saved, HW_POWER_5VCTRL_VBUSVALID_TRSH) | + (p5vctrl_saved & HW_POWER_5VCTRL_PWRUP_VBUS_CMPS) | + (p5vctrl_saved & HW_POWER_5VCTRL_VBUSVALID_5VDETECT); + REG_WRITE(HW_POWER_BASE + HW_POWER_5VCTRL, p5vctrl); + + return; +} + +/* + * 5VCTRL DCDC enable sequence according to errata #5837 + */ +void +p5vctrl_enable_dcdc(void) +{ + uint32_t p5vctrl; + uint32_t p5vctrl_saved; + uint32_t pctrl; + uint32_t pctrl_saved; + + pctrl_saved = REG_READ(HW_POWER_BASE + HW_POWER_CTRL); + p5vctrl_saved = REG_READ(HW_POWER_BASE + HW_POWER_5VCTRL); + + /* Disable the power rail brownout interrupts. */ + REG_WRITE(HW_POWER_BASE + HW_POWER_CTRL_CLR, + HW_POWER_CTRL_ENIRQ_VDDA_BO | + HW_POWER_CTRL_ENIRQ_VDDD_BO | + HW_POWER_CTRL_ENIRQ_VDDIO_BO); + + /* Set the HW_POWER_5VCTRL PWRUP_VBUS_CMPS bit (may already be set) */ + REG_WRITE(HW_POWER_BASE + HW_POWER_5VCTRL_SET, + HW_POWER_5VCTRL_PWRUP_VBUS_CMPS); + + /* Set the HW_POWER_5VCTRL VBUSVALID_5VDETECT bit to 1 */ + REG_WRITE(HW_POWER_BASE + HW_POWER_5VCTRL_SET, + HW_POWER_5VCTRL_VBUSVALID_5VDETECT); + + /* Set the HW_POWER_5VCTRL VBUSVALID_TRSH to 0x0 (2.9 V) */ + REG_WRITE(HW_POWER_BASE + HW_POWER_5VCTRL_CLR, + HW_POWER_5VCTRL_VBUSVALID_TRSH); + + /* Disable VBUSDROOP status and interrupt. */ + REG_WRITE(HW_POWER_BASE + HW_POWER_CTRL_CLR, + (HW_POWER_CTRL_VDD5V_DROOP_IRQ | HW_POWER_CTRL_ENIRQ_VDD5V_DROOP)); + + /* Work over errata #2816 by disabling 5 V brownout while modifying + * ENABLE_DCDC. */ + REG_WRITE(HW_POWER_BASE + HW_POWER_5VCTRL_CLR, + HW_POWER_5VCTRL_PWDN_5VBRNOUT); + + /* Set the ENABLE_DCDC bit in HW_POWER_5VCTRL. */ + REG_WRITE(HW_POWER_BASE + HW_POWER_5VCTRL_SET, + HW_POWER_5VCTRL_ENABLE_DCDC); + + REG_WRITE(HW_POWER_BASE + HW_POWER_5VCTRL_SET, + HW_POWER_5VCTRL_PWDN_5VBRNOUT); + + delay_us(100); + + pctrl = REG_READ(HW_POWER_BASE + HW_POWER_CTRL); + /* VBUSVALID_IRQ is set. */ + if (__SHIFTOUT(pctrl, HW_POWER_CTRL_VBUSVALID_IRQ)) { + /* repeat the sequence for enabling the 4P2 regulator and DCDC + * from 4P2. */ + enable_4p2_linreg(); + } + /* Restore modified bits back to HW_POWER_CTRL. */ + if (pctrl_saved & HW_POWER_CTRL_ENIRQ_VDDA_BO) + REG_WRITE(HW_POWER_BASE + HW_POWER_CTRL_SET, + HW_POWER_CTRL_ENIRQ_VDDA_BO); + else + REG_WRITE(HW_POWER_BASE + HW_POWER_CTRL_CLR, + HW_POWER_CTRL_ENIRQ_VDDA_BO); + + if (pctrl_saved & HW_POWER_CTRL_ENIRQ_VDDD_BO) + REG_WRITE(HW_POWER_BASE + HW_POWER_CTRL_SET, + HW_POWER_CTRL_ENIRQ_VDDD_BO); + else + REG_WRITE(HW_POWER_BASE + HW_POWER_CTRL_CLR, + HW_POWER_CTRL_ENIRQ_VDDD_BO); + + if (pctrl_saved & HW_POWER_CTRL_ENIRQ_VDDIO_BO) + REG_WRITE(HW_POWER_BASE + HW_POWER_CTRL_SET, + HW_POWER_CTRL_ENIRQ_VDDIO_BO); + else + REG_WRITE(HW_POWER_BASE + HW_POWER_CTRL_CLR, + HW_POWER_CTRL_ENIRQ_VDDIO_BO); + + if (pctrl_saved & HW_POWER_CTRL_VDD5V_DROOP_IRQ) + REG_WRITE(HW_POWER_BASE + HW_POWER_CTRL_SET, + HW_POWER_CTRL_VDD5V_DROOP_IRQ); + else + REG_WRITE(HW_POWER_BASE + HW_POWER_CTRL_CLR, + HW_POWER_CTRL_VDD5V_DROOP_IRQ); + + if (pctrl_saved & HW_POWER_CTRL_ENIRQ_VDD5V_DROOP) + REG_WRITE(HW_POWER_BASE + HW_POWER_CTRL_SET, + HW_POWER_CTRL_ENIRQ_VDD5V_DROOP); + else + REG_WRITE(HW_POWER_BASE + HW_POWER_CTRL_CLR, + HW_POWER_CTRL_ENIRQ_VDD5V_DROOP); + + /* Restore modified bits back to HW_POWER_5VCTRL. */ + p5vctrl = REG_READ(HW_POWER_BASE + HW_POWER_5VCTRL); + p5vctrl &= ~(HW_POWER_5VCTRL_PWRUP_VBUS_CMPS | + HW_POWER_5VCTRL_VBUSVALID_5VDETECT | + HW_POWER_5VCTRL_VBUSVALID_TRSH); + p5vctrl |= __SHIFTOUT(p5vctrl_saved, HW_POWER_5VCTRL_VBUSVALID_TRSH) | + (p5vctrl_saved & HW_POWER_5VCTRL_PWRUP_VBUS_CMPS) | + (p5vctrl_saved & HW_POWER_5VCTRL_VBUSVALID_5VDETECT); + REG_WRITE(HW_POWER_BASE + HW_POWER_5VCTRL, p5vctrl); + + return; +} + +void +enable_vddmem(void) +{ + uint32_t vddctrl; + + /* VDDMEM */ + vddctrl = REG_READ(HW_POWER_BASE + HW_POWER_VDDMEMCTRL); + vddctrl |= (HW_POWER_VDDMEMCTRL_PULLDOWN_ACTIVE | + HW_POWER_VDDMEMCTRL_ENABLE_ILIMIT | + HW_POWER_VDDMEMCTRL_ENABLE_LINREG); + REG_WRITE(HW_POWER_BASE + HW_POWER_VDDMEMCTRL, vddctrl); + delay_us(500); + vddctrl &= ~(HW_POWER_VDDMEMCTRL_PULLDOWN_ACTIVE | + HW_POWER_VDDMEMCTRL_ENABLE_ILIMIT); + REG_WRITE(HW_POWER_BASE + HW_POWER_VDDMEMCTRL, vddctrl); + + return; +}