Index: sys/arm/arm/elf_trampoline.c =================================================================== --- sys/arm/arm/elf_trampoline.c (revision 220086) +++ sys/arm/arm/elf_trampoline.c (working copy) @@ -72,7 +72,10 @@ #define cpu_idcache_wbinv_all xscale_cache_purgeID #elif defined(CPU_XSCALE_81342) #define cpu_idcache_wbinv_all xscalec3_cache_purgeID +#elif defined(CPU_CORTEXA8_OMAP3) +#define cpu_idcache_wbinv_all cortexa8_idcache_wbinv_all #endif + #ifdef CPU_XSCALE_81342 #define cpu_l2cache_wbinv_all xscalec3_l2cache_purge #elif defined(SOC_MV_KIRKWOOD) || defined(SOC_MV_DISCOVERY) Index: sys/arm/arm/cpufunc.c =================================================================== --- sys/arm/arm/cpufunc.c (revision 220086) +++ sys/arm/arm/cpufunc.c (working copy) @@ -83,6 +83,11 @@ #include #endif +#ifdef CPU_CORTEXA8_OMAP3 +#include +#include +#endif + /* PRIMARY CACHE VARIABLES */ int arm_picache_size; int arm_picache_line_size; @@ -844,6 +849,68 @@ }; #endif /* CPU_FA526 || CPU_FA626TE */ +#ifdef CPU_CORTEXA8_OMAP3 +struct cpu_functions cortexa8_cpufuncs = { + /* CPU functions */ + + .cf_id = cpufunc_id, /* id */ + .cf_cpwait = cpufunc_nullop, /* cpwait */ + + /* MMU functions */ + + .cf_control = cpufunc_control, /* control */ + .cf_domains = cpufunc_domains, /* Domain */ + .cf_setttb = cortexa8_setttb, /* Setttb */ + .cf_faultstatus = cpufunc_faultstatus, /* Faultstatus */ + .cf_faultaddress = cpufunc_faultaddress, /* Faultaddress */ + + /* TLB functions */ + + .cf_tlb_flushID = armv4_tlb_flushID, /* tlb_flushID */ + .cf_tlb_flushID_SE = cortexa8_tlb_flushID_SE, /* tlb_flushID_SE */ + .cf_tlb_flushI = armv4_tlb_flushI, /* tlb_flushI */ + .cf_tlb_flushI_SE = cortexa8_tlb_flushI_SE, /* tlb_flushI_SE */ + .cf_tlb_flushD = armv4_tlb_flushD, /* tlb_flushD */ + .cf_tlb_flushD_SE = armv4_tlb_flushD_SE, /* tlb_flushD_SE */ + + /* Cache operations */ + + .cf_icache_sync_all = cortexa8_icache_sync_all, /* icache_sync_all */ + .cf_icache_sync_range = cortexa8_icache_sync_range, /* icache_sync_range */ + + .cf_dcache_wbinv_all = cortexa8_dcache_wbinv_all, /* dcache_wbinv_all */ + .cf_dcache_wbinv_range = cortexa8_dcache_wbinv_range, /* dcache_wbinv_range */ + .cf_dcache_inv_range = cortexa8_dcache_inv_range, /* dcache_inv_range */ + .cf_dcache_wb_range = cortexa8_dcache_wb_range, /* dcache_wb_range */ + + .cf_idcache_wbinv_all = cortexa8_idcache_wbinv_all, /* idcache_wbinv_all */ + .cf_idcache_wbinv_range = cortexa8_idcache_wbinv_range, /* idcache_wbinv_range */ + + .cf_l2cache_wbinv_all = cpufunc_nullop, /* l2cache_wbinv_all */ + .cf_l2cache_wbinv_range = (void *)cpufunc_nullop, /* l2cache_wbinv_range */ + .cf_l2cache_inv_range = (void *)cpufunc_nullop, /* l2cache_inv_range */ + .cf_l2cache_wb_range = (void *)cpufunc_nullop, /* l2cache_wb_range */ + + /* Other functions */ + + .cf_flush_prefetchbuf = cpufunc_nullop, /* flush_prefetchbuf */ + .cf_drain_writebuf = cortexa8_drain_writebuf, /* drain_writebuf */ + .cf_flush_brnchtgt_C = cpufunc_nullop, /* flush_brnchtgt_C */ + .cf_flush_brnchtgt_E = cortexa8_flush_brnchtgt_E, /* flush_brnchtgt_E */ + + .cf_sleep = (void *)cpufunc_nullop, /* sleep */ + + /* Soft functions */ + + .cf_dataabt_fixup = cpufunc_null_fixup, /* dataabt_fixup */ + .cf_prefetchabt_fixup = cpufunc_null_fixup, /* prefetchabt_fixup */ + + .cf_context_switch = cortexa8_context_switch, /* context_switch */ + + .cf_setup = cortexa8_setup /* cpu setup */ + +}; +#endif /* CPU_CORTEXA8_OMAP3 */ /* * Global constants also used by locore.s @@ -938,6 +1005,85 @@ } #endif /* ARM7TDMI || ARM8 || ARM9 || XSCALE */ +#if defined(CPU_CORTEXA8_OMAP3) +static void get_cachetype_cp15(void); + +static void +get_cachetype_cp15() +{ + u_int ctype; + u_int selection; + u_int l1_dcachesize, l1_icachesize; + u_int cortexa8_icache_numsets; + u_int cortexa8_dcache_numsets; + + /* Read the cache type register */ + __asm __volatile("mrc p15, 0, %0, c0, c0, 1" + : "=r" (ctype)); + + + /* Read the L1 cache size identification register */ + selection = 0x0; + __asm __volatile("mcr p15, 2, %0, c0, c0, 0" + : : "r" (selection)); + __asm __volatile("mrc p15, 1, %0, c0, c0, 0" + : "=r" (l1_dcachesize)); + + /* Read the L2 cache size identification register */ + selection = 0x1; + __asm __volatile("mcr p15, 2, %0, c0, c0, 0" + : : "r" (selection)); + __asm __volatile("mrc p15, 1, %0, c0, c0, 0" + : "=r" (l1_icachesize)); + + +#if 0 + /* PRIMARY CACHE VARIABLES */ + extern int arm_picache_size; + extern int arm_picache_line_size; + extern int arm_picache_ways; + + extern int arm_pdcache_size; /* and unified */ + extern int arm_pdcache_line_size; + extern int arm_pdcache_ways; + + extern int arm_pcache_type; + extern int arm_pcache_unified; + + extern int arm_dcache_align; + extern int arm_dcache_align_mask; +#endif + + + /* Cortex has seperate instruction and data caches ... I think */ + arm_pcache_unified = 0; + + printf("l1_icachesize=0x%08x l1_dcachesize=0x%08x\n", + l1_icachesize, l1_dcachesize); + + /* get the icache information */ + arm_picache_line_size = 1 << ((l1_icachesize & 0x7) + 4); + arm_picache_ways = ((l1_icachesize >> 3) & 0x3FF) + 1; + cortexa8_icache_numsets = ((l1_icachesize >> 13) & 0x7FFF) + 1; + arm_picache_size = arm_picache_line_size * arm_picache_ways * + cortexa8_icache_numsets; + printf("arm_picache_line_size=%d arm_picache_ways=%d cortexa8_icache_numsets=%d arm_picache_size=%d\n", + arm_picache_line_size, arm_picache_ways, cortexa8_icache_numsets, arm_picache_size); + + /* get the dcache information */ + arm_pdcache_line_size = 1 << ((l1_dcachesize & 0x7) + 4); + arm_pdcache_ways = ((l1_dcachesize >> 3) & 0x3FF) + 1; + cortexa8_dcache_numsets = ((l1_dcachesize >> 13) & 0x7FFF) + 1; + arm_pdcache_size = arm_pdcache_line_size * arm_pdcache_ways * + cortexa8_dcache_numsets; + printf("arm_pdcache_line_size=%d arm_pdcache_ways=%d cortexa8_dcache_numsets=%d arm_pdcache_size=%d\n", + arm_pdcache_line_size, arm_pdcache_ways, cortexa8_dcache_numsets, arm_pdcache_size); + + arm_dcache_align = arm_pdcache_line_size; + arm_dcache_align_mask = arm_dcache_align - 1; +} +#endif /* CPU_CORTEXA8_OMAP3E */ + #if defined(CPU_SA110) || defined(CPU_SA1100) || defined(CPU_SA1110) || \ defined(CPU_IXP12X0) /* Cache information for CPUs without cache type registers. */ @@ -1254,6 +1400,19 @@ goto out; } #endif /* CPU_XSCALE_IXP425 */ +#ifdef CPU_CORTEXA8_OMAP3 + if (cputype == CPU_ID_CORTEXA8R1 || cputype == CPU_ID_CORTEXA8R2 || + cputype == CPU_ID_CORTEXA8R3 || cputype == CPU_ID_CORTEXA9R1) { + + cpufuncs = cortexa8_cpufuncs; + cpu_reset_needs_v4_MMU_disable = 1; /* V4 or higher */ + get_cachetype_cp15(); + + pmap_pte_init_armv7(); + + goto out; + } +#endif /* CPU_CORTEXA8_OMAP3 */ /* * Bzzzz. And the answer was ... */ @@ -1629,7 +1788,8 @@ defined(CPU_XSCALE_PXA2X0) || defined(CPU_XSCALE_IXP425) || \ defined(CPU_XSCALE_80219) || defined(CPU_XSCALE_81342) || \ defined(CPU_ARM10) || defined(CPU_ARM11) || \ - defined(CPU_FA526) || defined(CPU_FA626TE) + defined(CPU_FA526) || defined(CPU_FA626TE) || \ + defined(CPU_CORTEXA8_OMAP3) #define IGN 0 #define OR 1 @@ -1978,6 +2138,57 @@ } #endif /* CPU_ARM11 */ +#ifdef CPU_CORTEXA8_OMAP3 +struct cpu_option cortexa8_options[] = { + { "cpu.cache", BIC, OR, (CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE) }, + { "cpu.nocache", OR, BIC, (CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE) }, + { "cortex.cache", BIC, OR, (CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE) }, + { "cortex.icache", BIC, OR, CPU_CONTROL_IC_ENABLE }, + { "cortex.dcache", BIC, OR, CPU_CONTROL_DC_ENABLE }, + { NULL, IGN, IGN, 0 } +}; + +void +cortexa8_setup(args) + char *args; +{ + int cpuctrl, cpuctrlmask; + + cpuctrlmask = CPU_CONTROL_MMU_ENABLE | /* MMU enable [0] */ + CPU_CONTROL_AFLT_ENABLE | /* Alignment fault [1] */ + CPU_CONTROL_DC_ENABLE | /* DCache enable [2] */ + CPU_CONTROL_BPRD_ENABLE | /* Branch prediction [11] */ + CPU_CONTROL_IC_ENABLE | /* ICache enable [12] */ + CPU_CONTROL_VECRELOC; /* Vector relocation [13] */ + + cpuctrl = CPU_CONTROL_MMU_ENABLE | + CPU_CONTROL_IC_ENABLE | + CPU_CONTROL_DC_ENABLE | + 0 /* CPU_CONTROL_BPRD_ENABLE */; + +#ifndef ARM32_DISABLE_ALIGNMENT_FAULTS + cpuctrl |= CPU_CONTROL_AFLT_ENABLE; +#endif + + /* Parse options, can control whether caches are turned on or off */ + cpuctrl = parse_cpu_options(args, cortexa8_options, cpuctrl); + + /* Check if the vector page is at the high address (0xffff0000) */ + if (vector_page == ARM_VECTORS_HIGH) + cpuctrl |= CPU_CONTROL_VECRELOC; + + /* Clear out the cache */ + cpu_idcache_wbinv_all(); + + /* Set the control register */ + ctrl = cpuctrl; + cpu_control(cpuctrlmask, cpuctrl); + + /* And again. */ + cpu_idcache_wbinv_all(); +} +#endif /* CPU_CORTEXA8_OMAP3 */ + #ifdef CPU_SA110 struct cpu_option sa110_options[] = { #ifdef COMPAT_12 Index: sys/arm/arm/pmap.c =================================================================== --- sys/arm/arm/pmap.c (revision 220086) +++ sys/arm/arm/pmap.c (working copy) @@ -554,6 +554,72 @@ } #endif /* CPU_ARM10 */ +#if ARM_MMU_ARMV7 == 1 +void +pmap_pte_init_armv7(void) +{ + /* We use write through caching for now ... don't + * know why, but thats what some of the other platforms use. + * + * T E X C B + * 1 B B A A + * + * AA and BB are encoded as follows, AA = inner cache, BB = outer cache + * + * Encoding Cache attribute + * 0 0 Non-cacheable + * 0 1 Write-Back, Write-Allocate + * 1 0 Write-Through, no Write-Allocate + * 1 1 Write-Back, no Write-Allocate + */ +#if 0 + pte_l1_s_cache_mode = L1_S_C | L1_S_ARMV7_TEX(0x6); + pte_l1_s_cache_mask = L1_S_C | L1_S_B | L1_S_ARMV7_TEX_MASK; + + pte_l2_l_cache_mode = L2_C | L2_L_ARMV7_TEX(0x6); + pte_l2_l_cache_mask = L2_C | L2_B | L2_L_ARMV7_TEX_MASK; + + pte_l2_s_cache_mode = L2_C | L2_S_ARMV7_TEX(0x6); + pte_l2_s_cache_mask = L2_C | L2_B | L2_S_ARMV7_TEX_MASK; + + /* Caching modes for the page tables */ + pte_l1_s_cache_mode_pt = L1_S_C | L1_S_ARMV7_TEX(0x6); + pte_l2_l_cache_mode_pt = L2_C | L2_L_ARMV7_TEX(0x6); + pte_l2_s_cache_mode_pt = L2_C | L2_S_ARMV7_TEX(0x6); +#endif + pte_l1_s_cache_mode = L1_S_ARMV7_TEX(1); + pte_l1_s_cache_mask = L1_S_ARMV7_TEX_MASK|L1_S_B|L1_S_C; + + pte_l2_l_cache_mode = L2_L_ARMV7_TEX(1); + pte_l2_l_cache_mask = L2_L_ARMV7_TEX_MASK|L2_B|L2_C; + + pte_l2_s_cache_mode = L2_S_ARMV7_TEX(1); + pte_l2_s_cache_mask = L2_S_ARMV7_TEX_MASK|L2_B|L2_C; + + /* Caching modes for the page tables */ + pte_l1_s_cache_mode_pt = L1_S_ARMV7_TEX(1); + pte_l2_l_cache_mode_pt = L2_L_ARMV7_TEX(1); + pte_l2_s_cache_mode_pt = L2_S_ARMV7_TEX(1); + + + + /* These variables shouldn't be used on ARMv7, they don't encode + * enough information. + */ + pte_l2_s_prot_u = L2_S_PROT_U_armv7; + pte_l2_s_prot_w = L2_S_PROT_U_armv7; + pte_l2_s_prot_mask = L2_S_PROT_MASK_armv7; + + pte_l1_s_proto = L1_S_PROTO_armv7; + pte_l1_c_proto = L1_C_PROTO_armv7; + pte_l2_s_proto = L2_S_PROTO_generic; + + pmap_copy_page_func = pmap_copy_page_generic; + pmap_zero_page_func = pmap_zero_page_generic; +} +#endif /* ARM_MMU_ARMV7 == 1 */ + + #if ARM_MMU_SA1 == 1 void pmap_pte_init_sa1(void) @@ -4001,7 +4067,7 @@ * StrongARM accesses to non-cached pages are non-burst making writing * _any_ bulk data very slow. */ -#if (ARM_MMU_GENERIC + ARM_MMU_SA1) != 0 || defined(CPU_XSCALE_CORE3) +#if (ARM_MMU_GENERIC + ARM_MMU_SA1 + ARM_MMU_ARMV7) != 0 || defined(CPU_XSCALE_CORE3) void pmap_zero_page_generic(vm_paddr_t phys, int off, int size) { @@ -4051,7 +4117,7 @@ mtx_unlock(&cmtx); #endif } -#endif /* (ARM_MMU_GENERIC + ARM_MMU_SA1) != 0 */ +#endif /* (ARM_MMU_GENERIC + ARM_MMU_SA1 + ARM_MMU_ARMV7) != 0 */ #if ARM_MMU_XSCALE == 1 void @@ -4280,7 +4346,7 @@ * hook points. The same comment regarding cachability as in * pmap_zero_page also applies here. */ -#if (ARM_MMU_GENERIC + ARM_MMU_SA1) != 0 || defined (CPU_XSCALE_CORE3) +#if (ARM_MMU_GENERIC + ARM_MMU_SA1 + ARM_MMU_ARMV7) != 0 || defined (CPU_XSCALE_CORE3) void pmap_copy_page_generic(vm_paddr_t src, vm_paddr_t dst) { @@ -4329,7 +4395,7 @@ cpu_l2cache_inv_range(csrcp, PAGE_SIZE); cpu_l2cache_wbinv_range(cdstp, PAGE_SIZE); } -#endif /* (ARM_MMU_GENERIC + ARM_MMU_SA1) != 0 */ +#endif /* (ARM_MMU_GENERIC + ARM_MMU_SA1 + ARM_MMU_ARMV7) != 0 */ #if ARM_MMU_XSCALE == 1 void @@ -4829,6 +4895,7 @@ /* Use a small page mapping. */ #ifdef VERBOSE_INIT_ARM printf("P"); + printf(" [0x%08x]", (L2_S_PROTO | pa | L2_S_PROT(PTE_KERNEL, prot) | f2s)); #endif pte[l2pte_index(va)] = L2_S_PROTO | pa | L2_S_PROT(PTE_KERNEL, prot) | f2s; @@ -4924,3 +4991,290 @@ return (NULL); } + +#if 0 +/** + * pmap_dump_l2_entry - dumps a single L2 entry + * @va: the virtual address of top level PTE. + * @pte: the actual PTE entry. + * + * + * + * LOCKING: + * None required + * + * RETURNS: + * nothing + */ +static void +pmap_dump_l2_entry(vm_offset_t va, uint32_t pte) +{ + switch (pte & 0x3) { + case 0x0: + printf("[0x%08x]\t -> L2 L [0x%08x] {0x%08x} FAULT\n", + va, + pte, + (pte & 0xFFFF0000)); + break; + case 0x1: + printf("[0x%08x]\t -> L2 L [0x%08x] {0x%08x} XN:%d TEX:%d nG:%d S:%d AP:%d SBZ:%d AP:%d C:%d B:%d\n", + va, + pte, + (pte & 0xFFFF0000), + ((pte >> 15) & 0x1), + ((pte >> 12) & 0x7), + ((pte >> 11) & 0x1), + ((pte >> 10) & 0x1), + ((pte >> 9) & 0x1), + ((pte >> 6) & 0x7), + ((pte >> 4) & 0x3), + ((pte >> 3) & 0x1), + ((pte >> 2) & 0x1)); + break; + case 0x2: + case 0x3: + printf("[0x%08x]\t -> L2 S [0x%08x] {0x%08x} nG:%d S:%d AP:%d TEX:%d AP:%d C:%d B:%d XN:%d\n", + va, + pte, + (pte & 0xFFFFF000), + ((pte >> 11) & 0x1), + ((pte >> 10) & 0x1), + ((pte >> 9) & 0x1), + ((pte >> 6) & 0x7), + ((pte >> 4) & 0x3), + ((pte >> 3) & 0x1), + ((pte >> 2) & 0x1), + ((pte >> 0) & 0x1)); + break; + } +} + + + +/** + * pmap_dump_l2_entries - dumps L2 entries + * @va: the virtual address of top level PTE. + * @off: the offset from the L1 level. + * + * + * + * LOCKING: + * None required + * + * RETURNS: + * nothing + */ +#if 0 +static void +pmap_dump_l2_entries_phys(vm_offset_t va, vm_offset_t off) +{ + uint32_t i; + volatile uint32_t *p_pte = (volatile uint32_t*) va; + + printf("\tDumping L2 @ 0x%08x\n", va); + + for (i=0; i<256; i++) { + pmap_dump_l2_entry((off + (i * 4096)), *p_pte++); + } +} +#endif + +static void +pmap_dump_l2_entries(pmap_t pm, vm_offset_t va) +{ + u_int l1idx; + u_int l2idx; + struct l2_dtable *l2; + pt_entry_t *ptep; + uint32_t pte; + int print_elipses = 1; + + l1idx = (va >> L1_S_SHIFT); + l2 = pm->pm_l2[L2_IDX(l1idx)]; + + if (l2 != NULL && (ptep = l2->l2_bucket[L2_BUCKET(l1idx)].l2b_kva) != NULL) { + + for (l2idx = 0; l2idx < (L2_TABLE_SIZE / 4); l2idx++) { + pte = ptep[l2idx]; + + if (pte == 0x0) { + if (print_elipses) + printf("...\n"); + print_elipses = 0; + continue; + } + + pmap_dump_l2_entry((va + (l2idx << L2_S_SHIFT)), pte); + print_elipses = 1; + } + } + +} + + + + +#define PHSY2VIRT(a) (((a) - PHYSADDR) + KERNBASE) + +/** + * pmap_dump_l1_entry - dumps an L1 entry + * @va: the virtual address of top level PTE. + * @pte: the page table entry. + * + * + * + * LOCKING: + * None required + * + * RETURNS: + * nothing + */ +static void +pmap_dump_l1_entry(pmap_t pm, vm_offset_t va, uint32_t pte) +{ + switch (pte & 0x3) { + case 0x0: + printf("[0x%08x] -> L1 P [0x%08x] {0x%08x} FAULT\n", + va, + pte, + (pte & 0xFFFFFC00)); + break; + case 0x1: + printf("[0x%08x] -> L1 P [0x%08x] {0x%08x} IMP:%d D:%d SBZ:%d NS:%d SBZ:%d\n", + va, + pte, + (pte & 0xFFFFFC00), + ((pte >> 9) & 0x1), + ((pte >> 5) & 0xF), + ((pte >> 4) & 0x1), + ((pte >> 3) & 0x1), + ((pte >> 2) & 0x1)); + + if (((pte >> 5) & 0xF) == 0x1) { + pmap_dump_l2_entries(pm, va); + //pmap_dump_l2_entries_phys(PHSY2VIRT(pte & 0xFFFFFC00), va); + } +/* + l2 = pm->pm_l2[L2_IDX(l1idx)]; + if (l2 != NULL && (ptep = l2->l2_bucket[L2_BUCKET(l1idx)].l2b_kva) != NULL) { + + for (l2idx = 0; l2idx < (L2_TABLE_SIZE / 4); l2idx++) { + pte = ptep[l2idx]; + + if (pte == 0) + continue; + + pmap_dump_l2_entry((va + (l2idx << L2_S_SHIFT)), pte); + } +*/ + break; + case 0x2: + if (((pte >> 18) & 0x1) == 0) { + printf("[0x%08x] -> L1 S [0x%08x] {0x%08x} NS:%d 0:%d nG:%d S:%d AP2:%d TEX:%d AP:%d IMP:%d D:%d XN:%d C:%d B:%d\n", + va, + pte, + (pte & 0xFFF00000), + ((pte >> 19) & 0x1), + ((pte >> 18) & 0x1), + ((pte >> 17) & 0x1), + ((pte >> 16) & 0x1), + ((pte >> 15) & 0x1), + ((pte >> 12) & 0x7), + ((pte >> 10) & 0x3), + ((pte >> 9) & 0x1), + ((pte >> 5) & 0xF), + ((pte >> 4) & 0x1), + ((pte >> 3) & 0x1), + ((pte >> 2) & 0x1)); + } else { + printf("[0x%08x] -> L1 Ss[0x%08x] {0x%08x} EXT:%d NS:%d 1:%d nG:%d S:%d AP2:%d TEX:%d AP:%d IMP:%d EXT:%d XN:%d C:%d B:%d\n", + va, + pte, + (pte & 0xFF000000), + ((pte >> 20) & 0xF), + ((pte >> 19) & 0x1), + ((pte >> 18) & 0x1), + ((pte >> 17) & 0x1), + ((pte >> 16) & 0x1), + ((pte >> 15) & 0x1), + ((pte >> 12) & 0x7), + ((pte >> 10) & 0x3), + ((pte >> 9) & 0x1), + ((pte >> 5) & 0xF), + ((pte >> 4) & 0x1), + ((pte >> 3) & 0x1), + ((pte >> 2) & 0x1)); + } + break; + case 0x3: + printf("L1 Reservered\n"); + break; + } +} + +/* + * Routine: pmap_dump_ttb + * Function: + * Debugging routine to display the full TTB for a given map. + */ +void +pmap_dump_ttb(pmap_t pm) +{ + pd_entry_t l1pd; + u_int l1idx; + vm_offset_t va; + + printf("-------------------------------------------------------------\n"); + + PMAP_LOCK(pm); + + /* Loop through the entire table */ + for (l1idx = 0; l1idx < (L1_TABLE_SIZE / 4); l1idx++) { + l1pd = pm->pm_l1->l1_kva[l1idx]; + va = (l1idx << L1_S_SHIFT); + + pmap_dump_l1_entry(pm, va, l1pd); + } + + printf("-------------------------------------------------------------\n"); + + PMAP_UNLOCK(pm); +} + + +/* + * Routine: pmap_dump_section_at + * Function: + * Debugging routine to display the full TTB for a given map. + */ +void +pmap_dump_section_at(pmap_t pm, vm_offset_t va) +{ + pd_entry_t l1pd; + u_int l1idx; + + printf("-------------------------------------------------------------\n"); + + PMAP_LOCK(pm); + + l1idx = va >> L1_S_SHIFT; + + l1pd = pm->pm_l1->l1_kva[l1idx]; + va = (l1idx << L1_S_SHIFT); + + pmap_dump_l1_entry(pm, va, l1pd); + + printf("-------------------------------------------------------------\n"); + + PMAP_UNLOCK(pm); +} + + + +vm_offset_t +pmap_get_l1tbl(pmap_t pm) +{ + return ((vm_offset_t)pm->pm_l1->l1_kva); +} +#endif + Index: sys/arm/arm/cpufunc_asm_cortex_a8.S =================================================================== --- sys/arm/arm/cpufunc_asm_cortex_a8.S (revision 0) +++ sys/arm/arm/cpufunc_asm_cortex_a8.S (revision 0) @@ -0,0 +1,465 @@ +/* + * Copyright (c) 2010 + * Ben Gray . + * All rights reserved. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Ben Gray. + * 4. The name of the company nor the name of the author may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY BEN GRAY ``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 BEN GRAY 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. + */ + +/** + * This driver is heavily based on the ARM V5 CPU functions (located here + * cpufunc_asm_amrv5.S). Those assembly functions have the following copyright. + * + * + * Copyright (c) 2002, 2005 ARM Limited + * All rights reserved. + * + * 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. + * 3. The name of the company may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + */ + +/* + * ARMv7 Cortex assembly functions for CPU / MMU / TLB specific operations + * + * XXX We make no attempt at present to take advantage of the v7 memory + * architecture or ASID tagged TLBs. However this is still a work in progress + * so hopefully soon I'll get around to optimizing them. + * + */ + + + +#include +__FBSDID("$FreeBSD$"); + +/* + * Functions to set the MMU Translation Table Base register + * + * We need to clean and flush the cache as it uses virtual + * addresses that are about to change. + */ +ENTRY(cortexa8_setttb) + stmfd sp!, {r0, lr} + bl _C_LABEL(cortexa8_idcache_wbinv_all) + ldmfd sp!, {r0, lr} + + mcr p15, 0, r0, c2, c0, 0 /* load new TTB */ + + mcr p15, 0, r0, c8, c7, 0 /* invalidate I+D TLBs */ + mcr p15, 0, r0, c7, c10, 4 /* drain write buffer - data synchronization barrier */ + mov pc, lr + RET + +/* + * TLB functions + */ +ENTRY(cortexa8_tlb_flushID_SE) + mcr p15, 0, r0, c8, c6, 1 /* flush D tlb single entry */ + mcr p15, 0, r0, c8, c5, 1 /* flush I tlb single entry */ + mcr p15, 0, r0, c7, c10, 4 /* drain write buffer - data synchronization barrier */ + RET + +ENTRY(cortexa8_tlb_flushI_SE) + mcr p15, 0, r0, c8, c5, 1 /* flush I tlb single entry */ + mcr p15, 0, r0, c7, c10, 4 /* drain write buffer - - data synchronization barrier*/ + RET + +ENTRY(cortexa8_tlb_flushD_SE) + mcr p15, 0, r0, c8, c6, 1 /* flush D tlb single entry */ + mcr p15, 0, r0, c7, c10, 4 /* drain write buffer - data synchronization barrier */ + RET + + + +/* + * Context switch. + * + * These is the CPU-specific parts of the context switcher cpu_switch() + * These functions actually perform the TTB reload. + * + * NOTE: Special calling convention + * r1, r4-r13 must be preserved + */ +ENTRY(cortexa8_context_switch) + /* + * We can assume that the caches will only contain kernel addresses + * at this point. So no need to flush them again. + */ + mcr p15, 0, r0, c7, c10, 4 /* drain the write buffer - aka "Data Synchronization Barrier" (DSB) */ + mcr p15, 0, r0, c2, c0, 0 /* set the new TTB */ + mcr p15, 0, r0, c8, c7, 0 /* and flush the I+D tlbs */ + + /* Paranoia -- make sure the pipeline is empty. */ + nop + nop + nop + RET + + +/* + * Flush Branch Prediction Array + * + * + */ +ENTRY(cortexa8_flush_brnchtgt_E) + mcr p15, 0, r0, c7, c5, 7 /* invalidate VA from branch predictor array */ + mov pc, lr + +ENTRY(cortexa8_flush_brnchtgt_C) + mov r0, #0 + mcr p15, 0, r0, c7, c5, 6 /* invalidate entire branch predictor array */ + mov pc, lr + + +/* + * TLB functions + */ +ENTRY(cortexa8_tlb_flushID) + mcr p15, 0, r0, c8, c7, 0 /* flush I+D tlb */ + mcr p15, 0, r0, c7, c10, 4 /* drain write buffer - data synchronization barrier */ + mov pc, lr + +ENTRY(cortexa8_tlb_flushI) + mcr p15, 0, r0, c8, c5, 0 /* flush I tlb */ + mcr p15, 0, r0, c7, c10, 4 /* drain write buffer - data synchronization barrier */ + mov pc, lr + +ENTRY(cortexa8_tlb_flushD) + mcr p15, 0, r0, c8, c6, 0 /* flush D tlb */ + mcr p15, 0, r0, c7, c10, 4 /* drain write buffer - data synchronization barrier */ + mov pc, lr + +/* + * Other functions + */ +ENTRY(cortexa8_drain_writebuf) + mcr p15, 0, r0, c7, c10, 4 /* drain write buffer - aka "Data Synchronization Barrier" (DSB) */ + mov pc, lr /* see page 3-97 of the Cortex-A8 reference manual */ + +ENTRY(cortexa8_get_dcache_linesize) + mov r0, #0x0 + mcr p15, 2, r0, c0, c0, 0 /* set the cache selection register to 0x0 (L1 dcache) */ + mrc p15, 1, r0, c0, c0, 0 /* read the cache size identification register */ + and r0, r0, #0x7 + add r0, r0, #2 + mov ip, #1 + mov r0, ip, LSL r0 + RET + + + +#if 0 +ENTRY(cortexa8_get_cache_info) + mov ip, #0x0 + mcr p15, 2, ip, c0, c0, 0 /* set the cache selection register to 0x0 (L1 dcache) */ + mrc p15, 1, ip, c0, c0, 0 /* read the cache size identification register */ + mov s_max, ip, LSL#4 /* get the number of sets [bits 27:13] */ + mov s_max, s_max, LSR#17 + mov s_max, s_max, LSL#6 /* set is in bits [11:6] */ + mov s_inc, #(1<<6) + mov w_max, ip, LSL#19 /* get the number of ways [bits 12:3] */ + mov w_max, w_max, LSR#22 + mov w_max, w_max, LSL#30 /* way is in bits [31:30] */ + mov w_inc, #(1<<30) + ldr ip, .Lcortexa8_dcache_data + stmia ip, {s_max, i_max, s_inc, i_inc} + + mov ip, #0x1 + mcr p15, 2, ip, c0, c0, 0 /* set the cache selection register to 0x0 (L1 dcache) */ + mrc p15, 1, ip, c0, c0, 0 /* read the cache size identification register */ + mov s_max, ip, LSL#4 /* get the number of sets [bits 27:13] */ + mov s_max, s_max, LSR#17 + mov s_max, s_max, LSL#6 /* set is in bits [11:6] */ + mov s_inc, #(1<<6) + mov w_max, ip, LSL#19 /* get the number of ways [bits 12:3] */ + mov w_max, w_max, LSR#22 + mov w_max, w_max, LSL#30 /* way is in bits [31:30] */ + mov w_inc, #(1<<30) + ldr ip, .Lcortexa8_icache_data + stmia ip, {s_max, i_max, s_inc, i_inc} + + RET +#endif + + + + +/** + * @macro: get_cache_sets_way + * @desc: Gets the number of cache 'sets' and 'ways' + * @uses: ip + */ +.macro cortexa8_get_cache_sets_way cache s_max s_inc w_max w_inc + mov ip, #\cache + mcr p15, 2, ip, c0, c0, 0 /* set the cache selection register to 0x0 (L1 dcache) */ + mrc p15, 1, ip, c0, c0, 0 /* read the cache size identification register */ + + mov \s_max, ip, LSL#4 /* get the number of sets [bits 27:13] */ + mov \s_max, \s_max, LSR#17 + mov \s_max, \s_max, LSL#6 /* set is in bits [11:6] */ + mov \s_inc, #(1<<6) + + mov \w_max, ip, LSL#19 /* get the number of ways [bits 12:3] */ + mov \w_max, \w_max, LSR#22 + mov \w_max, \w_max, LSL#30 /* way is in bits [31:30] */ + mov \w_inc, #(1<<30) +.endm + + +/* + * Cache operations. For the entire cache we use the set/index + * operations. + */ + s_max .req r0 + w_max .req r1 + s_inc .req r2 + w_inc .req r3 + +.Lcortexa8_dcache_line_size: + .word _C_LABEL(arm_pdcache_line_size) +.Lcortexa8_icache_line_size: + .word _C_LABEL(arm_picache_line_size) + + +/** + * cortexa8_dcache_wb_range(vm_offset_t, vm_size_t) + * + * r0 = virtual_addr + * r1 = size + * + */ +ENTRY(cortexa8_dcache_wb_range) + ldr ip, .Lcortexa8_dcache_line_size + cmp r1, #0x4000 + bcs .Lcortexa8_dcache_wb + ldr ip, [ip] + sub r1, r1, #1 /* Don't overrun */ + sub r3, ip, #1 + and r2, r0, r3 + add r1, r1, r2 + bic r0, r0, r3 +.Lcortexa8_wb_next: + mcr p15, 0, r0, c7, c10, 1 /* Clean D cache SE with VA */ + add r0, r0, ip + subs r1, r1, ip + bpl .Lcortexa8_wb_next + mcr p15, 0, r0, c7, c10, 4 /* drain the write buffer */ + bx lr + + +/** + * cortexa8_icache_sync_range(vm_offset_t, vm_size_t) + * + * r0 = virtual_addr + * r1 = size + * + */ +ENTRY_NP(cortexa8_icache_sync_range) + ldr ip, .Lcortexa8_icache_line_size + cmp r1, #0x4000 + bcs .Lcortexa8_icache_sync_all + ldr ip, [ip] + sub r1, r1, #1 /* Don't overrun */ + sub r3, ip, #1 + and r2, r0, r3 + add r1, r1, r2 + bic r0, r0, r3 +.Lcortexa8_sync_next: + mcr p15, 0, r0, c7, c5, 1 /* Invalidate I cache SE with VA */ + mcr p15, 0, r0, c7, c10, 1 /* Clean D cache SE with VA */ + add r0, r0, ip + subs r1, r1, ip + bpl .Lcortexa8_sync_next + mcr p15, 0, r0, c7, c10, 4 /* drain the write buffer */ + bx lr + + +ENTRY_NP(cortexa8_icache_sync_all) +.Lcortexa8_icache_sync_all: + /* + * We assume that the code here can never be out of sync with the + * dcache, so that we can safely flush the Icache and fall through + * into the Dcache cleaning code. + */ + mcr p15, 0, r0, c7, c5, 0 /* Flush I cache */ + /* Fall through to clean Dcache. */ + +.Lcortexa8_dcache_wb: + cortexa8_get_cache_sets_way 0x0 s_max s_inc w_max w_inc +.Lnext_set: + orr ip, s_max, w_max +.Lnext_way: + mcr p15, 0, ip, c7, c10, 2 /* Clean D cache SE with Set/Index */ + sub ip, ip, w_inc + tst ip, w_max /* Index 0 is last one */ + bne .Lnext_way /* Next index */ + mcr p15, 0, ip, c7, c10, 2 /* Clean D cache SE with Set/Index */ + subs s_max, s_max, s_inc + bpl .Lnext_set /* Next set */ + mcr p15, 0, r0, c7, c10, 4 /* drain the write buffer */ + bx lr + + +/** + * cortexa8_dcache_wbinv_range(vm_offset_t, vm_size_t) + * + * r0 = virtual_addr + * r1 = size + * + */ +ENTRY(cortexa8_dcache_wbinv_range) + ldr ip, .Lcortexa8_dcache_line_size + cmp r1, #0x4000 + bcs .Lcortexa8_dcache_wbinv_all + ldr ip, [ip] + sub r1, r1, #1 /* Don't overrun */ + sub r3, ip, #1 + and r2, r0, r3 + add r1, r1, r2 + bic r0, r0, r3 +.Lcortexa8_wbinv_next: + mcr p15, 0, r0, c7, c14, 1 /* Purge D cache SE with VA */ + add r0, r0, ip + subs r1, r1, ip + bpl .Lcortexa8_wbinv_next + mcr p15, 0, r0, c7, c10, 4 /* drain the write buffer */ + bx lr + +/* + * Note, we must not invalidate everything. If the range is too big we + * must use wb-inv of the entire cache. + * + * r0 = virtual_addr + * r1 = size + */ +ENTRY(cortexa8_dcache_inv_range) + ldr ip, .Lcortexa8_dcache_line_size + cmp r1, #0x4000 + bcs .Lcortexa8_dcache_wbinv_all + ldr ip, [ip] /* ip = cache_line_size */ + sub r1, r1, #1 /* size -= 1 : Don't overrun */ + sub r3, ip, #1 /* r3 = cache_bitmask = (cache_line_size - 1) */ + and r2, r0, r3 /* r2 = vaddr & cache_bitmask */ + add r1, r1, r2 /* r1 = size = size + (vaddr & cache_bitmask) */ + bic r0, r0, r3 /* r0 = vaddr = vaddr & ~cache_bitmask */ +.Lcortexa8_inv_next: + mcr p15, 0, r0, c7, c6, 1 /* Invalidate D cache SE with VA */ + add r0, r0, ip + subs r1, r1, ip + bpl .Lcortexa8_inv_next + mcr p15, 0, r0, c7, c10, 4 /* drain the write buffer */ + bx lr + + +/** + * cortexa8_idcache_wbinv_range(vm_offset_t, vm_size_t) + * + * r0 = offset + * r1 = size + * + */ +ENTRY(cortexa8_idcache_wbinv_range) + ldr ip, .Lcortexa8_dcache_line_size + cmp r1, #0x4000 + bcs .Lcortexa8_idcache_wbinv_all + ldr ip, [ip] + sub r1, r1, #1 /* Don't overrun */ + sub r3, ip, #1 + and r2, r0, r3 + add r1, r1, r2 + bic r0, r0, r3 +.Lcortexa8_id_wbinv_next: + mcr p15, 0, r0, c7, c5, 1 /* Invalidate I cache SE with VA */ + mcr p15, 0, r0, c7, c14, 1 /* Purge D cache SE with VA */ + add r0, r0, ip + subs r1, r1, ip + bpl .Lcortexa8_id_wbinv_next + mcr p15, 0, r0, c7, c10, 4 /* drain the write buffer */ + bx lr + + + +/* + * + * + * There are some restrictions on the registers that this function can use + * (unless of course a stack is used). + * + * Can't use: r5, r6, r7, r8, r9, r10 + */ +ENTRY_NP(cortexa8_idcache_wbinv_all) +.Lcortexa8_idcache_wbinv_all: + /* + * We assume that the code here can never be out of sync with the + * dcache, so that we can safely flush the Icache and fall through + * into the Dcache purging code. + */ + mcr p15, 0, r0, c7, c5, 0 /* Flush I cache */ + /* Fall through to purge Dcache. */ + +ENTRY(cortexa8_dcache_wbinv_all) +.Lcortexa8_dcache_wbinv_all: + cortexa8_get_cache_sets_way 0x0 s_max s_inc w_max w_inc + +.Lnext_set_inv: + orr ip, s_max, w_max +.Lnext_way_inv: + mcr p15, 0, ip, c7, c14, 2 /* Purge D cache SE with Set/Index */ + sub ip, ip, w_inc + tst ip, w_max /* Index 0 is last one */ + bne .Lnext_way_inv /* Next way */ + mcr p15, 0, ip, c7, c14, 2 /* Purge D cache SE with Set/Index */ + subs s_max, s_max, s_inc + bpl .Lnext_set_inv /* Next set */ + + mcr p15, 0, r0, c7, c10, 4 /* drain the write buffer */ + bx lr + + + Index: sys/arm/arm/locore.S =================================================================== --- sys/arm/arm/locore.S (revision 220086) +++ sys/arm/arm/locore.S (working copy) @@ -47,7 +47,64 @@ * of the kernel text segment (not necessarily the same as kernbase). */ +/* [BRG] user_0 = gpio150, user_1 = gpio149 <==> GPIO5 Register set + * + */ +#define GPIO5_HWBASE 0x49056000 +#define GPIO5_HWBASE_1 0x49000000 +#define GPIO5_HWBASE_2 0x00056000 +#define GPIO5_VBASE 0xC9056000 +#define GPIO5_VBASE_1 0xC9000000 +#define GPIO5_VBASE_2 0x00056000 + + +#define GPIO_CTRL 0x030 +#define GPIO_OE 0x034 +#define GPIO_DATAOUT 0x03C + +#define GPIO22 0x400000 // (1UL << 22) +#define GPIO21 0x200000 // (1UL << 21) + +#define BRG_LED_SETUP(reg1, reg2) \ + mov reg1, #GPIO5_HWBASE_1 ;\ + add reg1, reg1, #GPIO5_HWBASE_2 ;\ + ldr reg2, [reg1, #GPIO_OE] ;\ + bic reg2, reg2, #GPIO22 ;\ + str reg2, [reg1, #GPIO_OE] + + +#define BRG_LED_0_ON(reg1, reg2) \ + mov reg1, #GPIO5_HWBASE_1 ;\ + add reg1, reg1, #GPIO5_HWBASE_2 ;\ + ldr reg2, [reg1, #GPIO_DATAOUT] ;\ + orr reg2, reg2, #GPIO22 ;\ + str reg2, [reg1, #GPIO_DATAOUT] + +#define BRG_LED_0_OFF(reg1, reg2) \ + mov reg1, #GPIO5_HWBASE_1 ;\ + add reg1, reg1, #GPIO5_HWBASE_2 ;\ + ldr reg2, [reg1, #GPIO_DATAOUT] ;\ + bic reg2, reg2, #GPIO22 ;\ + str reg2, [reg1, #GPIO_DATAOUT] + + +#define BRG_LED_1_ON(reg1, reg2) \ + mov reg1, #GPIO5_HWBASE_1 ;\ + add reg1, reg1, #GPIO5_HWBASE_2 ;\ + ldr reg2, [reg1, #GPIO_DATAOUT] ;\ + orr reg2, reg2, #GPIO21 ;\ + str reg2, [reg1, #GPIO_DATAOUT] + +#define BRG_LED_1_OFF(reg1, reg2) \ + mov reg1, #GPIO5_HWBASE_1 ;\ + add reg1, reg1, #GPIO5_HWBASE_2 ;\ + ldr reg2, [reg1, #GPIO_DATAOUT] ;\ + bic reg2, reg2, #GPIO21 ;\ + str reg2, [reg1, #GPIO_DATAOUT] + + + #define CPWAIT_BRANCH \ sub pc, pc, #4 @@ -84,9 +141,15 @@ orr r7, r7, #(I32_bit|F32_bit) msr cpsr_c, r7 + BRG_LED_SETUP(r7, r2) + BRG_LED_0_ON(r7, r2) + BRG_LED_1_ON(r7, r2) + #if defined (FLASHADDR) && defined(LOADERRAMADDR) /* Check if we're running from flash. */ ldr r7, =FLASHADDR + + /* * If we're running with MMU disabled, test against the * physical address instead. @@ -145,10 +208,10 @@ adr r4, mmu_init_table b 3f -2: - str r3, [r0, r2] +2: /* [BRG] Populates the page table */ + str r3, [r0, r2] /* [BRG] r0 = STARTUP_PAGETABLE_ADDR, r2 = 4*((VA)>>L1_S_SHIFT) */ add r2, r2, #4 - add r3, r3, #(L1_S_SIZE) + add r3, r3, #(L1_S_SIZE) /* [BRG] L1_S_SIZE = 1MB (Layer 1 page table entry) */ adds r1, r1, #-1 bhi 2b 3: @@ -174,6 +237,7 @@ nop CPWAIT(r0) + #endif mmu_done: nop @@ -219,11 +283,18 @@ .word STARTUP_PAGETABLE_ADDR mmu_init_table: /* fill all table VA==PA */ + + /* [BRG] map L4-Periph memory (contains GPIO, UART3 registers) to VA, not cached */ + MMU_INIT(0x49000000, 0x49000000, 1, L1_TYPE_S|L1_S_AP(AP_KRW)) + /* [BRG] map L4-Core memory to VA, not cached */ + //MMU_INIT(0x48000000, 0x48000000, 16, L1_TYPE_S|L1_S_AP(AP_KRW)) + /* map SDRAM VA==PA, WT cacheable */ MMU_INIT(PHYSADDR, PHYSADDR , 64, L1_TYPE_S|L1_S_C|L1_S_AP(AP_KRW)) /* map VA 0xc0000000..0xc3ffffff to PA */ MMU_INIT(KERNBASE, PHYSADDR, 64, L1_TYPE_S|L1_S_C|L1_S_AP(AP_KRW)) + .word 0 /* end of table */ #endif .Lstart: Index: sys/arm/arm/identcpu.c =================================================================== --- sys/arm/arm/identcpu.c (revision 220086) +++ sys/arm/arm/identcpu.c (working copy) @@ -305,6 +305,9 @@ { CPU_ID_MV88FR571_41, CPU_CLASS_MARVELL, "Early Feroceon 88FR571", generic_steppings }, + { CPU_ID_OMAP3530, CPU_CLASS_CORTEXA8, "TI OMAP3530", + generic_steppings }, + { 0, CPU_CLASS_NONE, NULL, NULL } }; @@ -331,6 +334,7 @@ { "XScale", "CPU_XSCALE_..." }, /* CPU_CLASS_XSCALE */ { "ARM11J", "CPU_ARM11" }, /* CPU_CLASS_ARM11J */ { "Marvell", "CPU_MARVELL" }, /* CPU_CLASS_MARVELL */ + { "Cortex-A8", "CPU_CORTEXA8" }, /* CPU_CLASS_CORTEXA8 */ }; /* @@ -406,6 +410,7 @@ case CPU_CLASS_SA1: case CPU_CLASS_XSCALE: case CPU_CLASS_ARM11J: + case CPU_CLASS_CORTEXA8: case CPU_CLASS_MARVELL: if ((ctrl & CPU_CONTROL_DC_ENABLE) == 0) printf(" DC disabled"); Index: sys/arm/include/cpuconf.h =================================================================== --- sys/arm/include/cpuconf.h (revision 220086) +++ sys/arm/include/cpuconf.h (working copy) @@ -63,7 +63,8 @@ defined(CPU_XSCALE_PXA2X0) + \ defined(CPU_FA526) + \ defined(CPU_FA626TE) + \ - defined(CPU_XSCALE_IXP425)) + defined(CPU_XSCALE_IXP425) + \ + defined(CPU_CORTEXA8_OMAP3)) /* * Step 2: Determine which ARM architecture versions are configured. @@ -92,12 +93,18 @@ #define ARM_ARCH_6 0 #endif -#define ARM_NARCH (ARM_ARCH_4 + ARM_ARCH_5 + ARM_ARCH_6) +#if defined(CPU_CORTEXA8_OMAP3) +#define ARM_ARCH_7 1 +#else +#define ARM_ARCH_7 0 +#endif + +#define ARM_NARCH (ARM_ARCH_4 + ARM_ARCH_5 + ARM_ARCH_6 + ARM_ARCH_7) #if ARM_NARCH == 0 && !defined(KLD_MODULE) && defined(_KERNEL) #error ARM_NARCH is 0 #endif -#if ARM_ARCH_5 || ARM_ARCH_6 +#if ARM_ARCH_5 || ARM_ARCH_6 || ARM_ARCH_7 /* * We could support Thumb code on v4T, but the lack of clean interworking * makes that hard. @@ -150,8 +157,14 @@ #define ARM_MMU_XSCALE 0 #endif +#if defined(CPU_CORTEXA8_OMAP3) +#define ARM_MMU_ARMV7 1 +#else +#define ARM_MMU_ARMV7 0 +#endif + #define ARM_NMMUS (ARM_MMU_MEMC + ARM_MMU_GENERIC + \ - ARM_MMU_SA1 + ARM_MMU_XSCALE) + ARM_MMU_SA1 + ARM_MMU_XSCALE + ARM_MMU_ARMV7) #if ARM_NMMUS == 0 && !defined(KLD_MODULE) && defined(_KERNEL) #error ARM_NMMUS is 0 #endif Index: sys/arm/include/intr.h =================================================================== --- sys/arm/include/intr.h (revision 220086) +++ sys/arm/include/intr.h (working copy) @@ -45,7 +45,7 @@ #elif defined(CPU_XSCALE_PXA2X0) #include #define NIRQ IRQ_GPIO_MAX -#elif defined(SOC_MV_DISCOVERY) +#elif defined(SOC_MV_DISCOVERY) || defined(CPU_CORTEXA8_OMAP3) #define NIRQ 96 #elif defined(CPU_ARM9) || defined(SOC_MV_KIRKWOOD) || \ defined(CPU_XSCALE_IXP435) Index: sys/arm/include/cpufunc.h =================================================================== --- sys/arm/include/cpufunc.h (revision 220086) +++ sys/arm/include/cpufunc.h (working copy) @@ -373,7 +373,7 @@ extern unsigned arm9_dcache_index_inc; #endif -#if defined(CPU_ARM9E) || defined(CPU_ARM10) +#if defined(CPU_ARM9E) || defined(CPU_ARM10) || defined(CPU_CORTEXA8_OMAP3) void arm10_setttb (u_int); void arm10_tlb_flushID_SE (u_int); @@ -445,7 +445,45 @@ void armv5_ec_idcache_wbinv_range(vm_offset_t, vm_size_t); #endif -#if defined (CPU_ARM10) || defined (CPU_ARM11) +#if defined(CPU_CORTEXA8_OMAP3) +void cortexa8_setttb (u_int); + +void cortexa8_tlb_flushID_SE (u_int); +void cortexa8_tlb_flushI_SE (u_int); + +void cortexa8_tlb_flushID (void); +void cortexa8_tlb_flushI (void); +void cortexa8_tlb_flushD (void); +void cortexa8_tlb_flushD_SE (u_int va); + +void cortexa8_drain_writebuf (void); + +void cortexa8_context_switch (void); + +void cortexa8_setup (char *string); + +void cortexa8_icache_sync_range(vm_offset_t, vm_size_t); +void cortexa8_icache_sync_all(void); + +void cortexa8_dcache_wb_range(vm_offset_t, vm_size_t); +void cortexa8_dcache_inv_range(vm_offset_t, vm_size_t); +void cortexa8_dcache_wbinv_range(vm_offset_t, vm_size_t); +void cortexa8_dcache_wbinv_all (void); + +void cortexa8_idcache_wbinv_range(vm_offset_t, vm_size_t); +void cortexa8_idcache_wbinv_all (void); + +void cortexa8_flush_brnchtgt_E (u_int); +void cortexa8_flush_brnchtgt_C (void); + +// extern unsigned cortexa8_dcache_sets_max; +// extern unsigned cortexa8_dcache_sets_inc; +// extern unsigned cortexa8_dcache_index_max; +// extern unsigned cortexa8_dcache_index_inc; + +#endif + +#if defined (CPU_ARM10) || defined (CPU_ARM11) || defined (CPU_CORTEXA8_OMAP3) void armv5_setttb(u_int); void armv5_icache_sync_all(void); @@ -470,7 +508,8 @@ defined(CPU_XSCALE_80200) || defined(CPU_XSCALE_80321) || \ defined(CPU_FA526) || defined(CPU_FA626TE) || \ defined(CPU_XSCALE_PXA2X0) || defined(CPU_XSCALE_IXP425) || \ - defined(CPU_XSCALE_80219) || defined(CPU_XSCALE_81342) + defined(CPU_XSCALE_80219) || defined(CPU_XSCALE_81342) || \ + defined(CPU_CORTEXA8_OMAP3) void armv4_tlb_flushID (void); void armv4_tlb_flushI (void); Index: sys/arm/include/pte.h =================================================================== --- sys/arm/include/pte.h (revision 220086) +++ sys/arm/include/pte.h (working copy) @@ -161,10 +161,12 @@ #define L2_S_FRAME (~L2_S_OFFSET) #define L2_S_SHIFT 12 +#if 0 #define L2_T_SIZE 0x00000400 /* 1K */ #define L2_T_OFFSET (L2_T_SIZE - 1) #define L2_T_FRAME (~L2_T_OFFSET) #define L2_T_SHIFT 10 +#endif /* * The NetBSD VM implementation only works on whole pages (4K), @@ -212,6 +214,17 @@ #define L1_S_SUPERSEC ((1) << 18) /* Section is a super-section. */ +#define L1_S_ARMV7_XN 0x00000010 /* ARMv7 execute-never bit */ +#define L1_S_ARMV7_TEX(x) ((x) << 12) /* ARMv7 Type Extension */ +#define L1_S_ARMV7_TEX_MASK L1_S_ARMV7_TEX(0x7) /* ARMv7 Type Extension */ + +#define L1_S_ARMV7_AP0(x) (((x) & 0x1) << 10) +#define L1_S_ARMV7_AP1(x) (((x) & 0x1) << 11) +#define L1_S_ARMV7_AP2(x) (((x) & 0x1) << 15) +#define L1_S_ARMV7_AP(x) (L1_S_ARMV7_AP0(x) | L1_S_ARMV7_AP1((x) >> 1) | \ + L1_S_ARMV7_AP2((x) >> 2)) + + /* L1 Coarse Descriptor */ #define L1_C_IMP0 0x00000004 /* implementation defined */ #define L1_C_IMP1 0x00000008 /* implementation defined */ @@ -222,6 +235,7 @@ #define L1_C_XSCALE_P 0x00000200 /* ECC enable for this section */ + /* L1 Fine Descriptor */ #define L1_F_IMP0 0x00000004 /* implementation defined */ #define L1_F_IMP1 0x00000008 /* implementation defined */ @@ -232,6 +246,7 @@ #define L1_F_XSCALE_P 0x00000200 /* ECC enable for this section */ + /* * ARM L2 Descriptors */ @@ -262,7 +277,44 @@ #define L2_XSCALE_L_S(x) (1 << 15) /* Shared */ #define L2_XSCALE_T_TEX(x) ((x) << 6) /* Type Extension */ +#define L2_L_ARMV7_TEX(x) ((x) << 12) /* ARMv7 Type Extension */ +#define L2_L_ARMV7_TEX_MASK L2_L_ARMV7_TEX(0x7) /* ARMv7 Type Extension */ + +#define L2_S_ARMV7_TEX(x) ((x) << 6) /* ARMv7 Type Extension */ +#define L2_S_ARMV7_TEX_MASK L2_S_ARMV7_TEX(0x7) /* ARMv7 Type Extension */ + + /* + * ARMv7 has a more complicated access permission model, it goes + * a little something like this: + * + * AP[2] AP[1:0] kernel user + * 0 00 NA NA All accesses generate Permission faults + * 0 01 R/W NA Privileged access only + * 0 10 R/W RO Writes in User mode generate Permission faults + * 0 11 R/W R/W Full access + * 1 00 - - Reserved + * 1 01 RO NA Privileged read-only + * 1 10 RO RO Privileged and User read-only, deprecated in VMSAv7a + * 1 11 RO RO Privileged and User read-only + * + * However it has a simplified mode, were you just set AP0 to 1 and then: + * AP[2] AP[1] Access + * 0 0 Kernel, read/write + * 0 1 User, read/write + * 1 0 Kernel, read-only + * 1 1 User, read-only + * + */ +#define L2_ARMV7_AP0(x) (((x) & 0x1) << 4) +#define L2_ARMV7_AP1(x) (((x) & 0x1) << 5) +#define L2_ARMV7_AP2(x) (((x) & 0x1) << 9) +#define L2_ARMV7_AP(x) (L2_ARMV7_AP0(x) | L2_ARMV7_AP1((x) >> 1) | \ + L2_ARMV7_AP2((x) >> 2)) + + + +/* * Access Permissions for L1 and L2 Descriptors. */ #define AP_W 0x01 /* writable */ Index: sys/arm/include/pmap.h =================================================================== --- sys/arm/include/pmap.h (revision 220086) +++ sys/arm/include/pmap.h (working copy) @@ -225,6 +225,15 @@ int pmap_fault_fixup(pmap_t, vm_offset_t, vm_prot_t, int); /* + * Debugging functions + */ +void pmap_dump_ttb(pmap_t pm); +void pmap_dump_section_at(pmap_t pm, vm_offset_t va); + +vm_offset_t pmap_get_l1tbl(pmap_t pm); + + +/* * Definitions for MMU domains */ #define PMAP_DOMAINS 15 /* 15 'user' domains (1-15) */ @@ -273,15 +282,21 @@ #define L2_S_PROT_W_xscale (L2_AP0(AP_W)) #define L2_S_PROT_MASK_xscale (L2_S_PROT_U|L2_S_PROT_W) +#define L2_S_PROT_U_armv7 (L2_ARMV7_AP(AP_U)) +#define L2_S_PROT_W_armv7 (L2_ARMV7_AP(AP_W)) +#define L2_S_PROT_MASK_armv7 (L2_ARMV7_AP(0x7)) + #define L2_S_CACHE_MASK_generic (L2_B|L2_C) #define L2_S_CACHE_MASK_xscale (L2_B|L2_C|L2_XSCALE_T_TEX(TEX_XSCALE_X)| \ L2_XSCALE_T_TEX(TEX_XSCALE_X)) #define L1_S_PROTO_generic (L1_TYPE_S | L1_S_IMP) #define L1_S_PROTO_xscale (L1_TYPE_S) +#define L1_S_PROTO_armv7 (L1_TYPE_S) #define L1_C_PROTO_generic (L1_TYPE_C | L1_C_IMP2) #define L1_C_PROTO_xscale (L1_TYPE_C) +#define L1_C_PROTO_armv7 (L1_TYPE_C) #define L2_L_PROTO (L2_TYPE_L) @@ -319,6 +334,19 @@ #define L1_C_PROTO L1_C_PROTO_generic #define L2_S_PROTO L2_S_PROTO_generic +#elif ARM_MMU_ARMV7 == 1 +#define L2_S_PROT_U L2_S_PROT_U_armv7 +#define L2_S_PROT_W L2_S_PROT_W_armv7 +#define L2_S_PROT_MASK L2_S_PROT_MASK_armv7 + +#define L1_S_CACHE_MASK pte_l1_s_cache_mask +#define L2_L_CACHE_MASK pte_l2_l_cache_mask +#define L2_S_CACHE_MASK pte_l2_s_cache_mask + +#define L1_S_PROTO L1_S_PROTO_armv7 +#define L1_C_PROTO L1_C_PROTO_armv7 +#define L2_S_PROTO L2_S_PROTO_generic + #elif ARM_MMU_XSCALE == 1 #define L2_S_PROT_U L2_S_PROT_U_xscale #define L2_S_PROT_W L2_S_PROT_W_xscale @@ -348,6 +376,28 @@ * These macros return various bits based on kernel/user and protection. * Note that the compiler will usually fold these at compile time. */ +#if ARM_MMU_ARMV7 == 1 + +#define L1_S_PROT(ku, pr) \ + (L1_S_ARMV7_AP0(1) | \ + (((ku) == PTE_USER) ? L1_S_ARMV7_AP1(1) : 0) | \ + ((((pr) & VM_PROT_WRITE) == 0) ? L1_S_ARMV7_AP2(1) : 0)) + +#define L2_L_PROT(ku, pr) \ + (L2_ARMV7_AP0(1) | \ + (((ku) == PTE_USER) ? L2_ARMV7_AP1(1) : 0) | \ + ((((pr) & VM_PROT_WRITE) == 0) ? L2_ARMV7_AP2(1) : 0)) + +#define L2_S_PROT(ku, pr) \ + (L2_ARMV7_AP0(1) | \ + (((ku) == PTE_USER) ? L2_ARMV7_AP1(1) : 0) | \ + ((((pr) & VM_PROT_WRITE) == 0) ? L2_ARMV7_AP2(1) : 0)) + +//#define L2_S_PROT_W(pte) (((pte) & L2_ARMV7_AP2(1)) == 0) +//#define L2_S_PROT_U(pte) (((pte) & L2_ARMV7_AP1(1)) == 1) + +#else + #define L1_S_PROT(ku, pr) ((((ku) == PTE_USER) ? L1_S_PROT_U : 0) | \ (((pr) & VM_PROT_WRITE) ? L1_S_PROT_W : 0)) @@ -357,6 +407,9 @@ #define L2_S_PROT(ku, pr) ((((ku) == PTE_USER) ? L2_S_PROT_U : 0) | \ (((pr) & VM_PROT_WRITE) ? L2_S_PROT_W : 0)) +#endif + + /* * Macros to test if a mapping is mappable with an L1 Section mapping * or an L2 Large Page mapping. @@ -418,7 +471,7 @@ extern void (*pmap_copy_page_func)(vm_paddr_t, vm_paddr_t); extern void (*pmap_zero_page_func)(vm_paddr_t, int, int); -#if (ARM_MMU_GENERIC + ARM_MMU_SA1) != 0 || defined(CPU_XSCALE_81342) +#if (ARM_MMU_GENERIC + ARM_MMU_SA1 + ARM_MMU_ARMV7) != 0 || defined(CPU_XSCALE_81342) void pmap_copy_page_generic(vm_paddr_t, vm_paddr_t); void pmap_zero_page_generic(vm_paddr_t, int, int); @@ -434,6 +487,10 @@ #endif /* CPU_ARM10 */ #endif /* (ARM_MMU_GENERIC + ARM_MMU_SA1) != 0 */ +#if ARM_MMU_ARMV7 == 1 +void pmap_pte_init_armv7(void); +#endif /* ARM_MMU_ARMV7 == 1 */ + #if /* ARM_MMU_SA1 == */1 void pmap_pte_init_sa1(void); #endif /* ARM_MMU_SA1 == 1 */ Index: sys/arm/include/md_var.h =================================================================== --- sys/arm/include/md_var.h (revision 220086) +++ sys/arm/include/md_var.h (working copy) @@ -65,7 +65,8 @@ CPU_CLASS_SA1, CPU_CLASS_XSCALE, CPU_CLASS_ARM11J, - CPU_CLASS_MARVELL + CPU_CLASS_MARVELL, + CPU_CLASS_CORTEXA8 }; extern enum cpu_class cpu_class; Index: sys/arm/include/armreg.h =================================================================== --- sys/arm/include/armreg.h (revision 220086) +++ sys/arm/include/armreg.h (working copy) @@ -145,6 +145,10 @@ #define CPU_ID_ARM1026EJS 0x4106a260 #define CPU_ID_ARM1136JS 0x4107b360 #define CPU_ID_ARM1136JSR1 0x4117b360 +#define CPU_ID_CORTEXA8R1 0x411fc080 +#define CPU_ID_CORTEXA8R2 0x412fc080 +#define CPU_ID_CORTEXA8R3 0x413fc080 +#define CPU_ID_CORTEXA9R1 0x411fc090 #define CPU_ID_SA110 0x4401a100 #define CPU_ID_SA1100 0x4401a110 #define CPU_ID_TI925T 0x54029250 @@ -178,6 +182,7 @@ #define CPU_ID_IXP425_266 0x690541f0 #define CPU_ID_IXP435 0x69054040 #define CPU_ID_IXP465 0x69054200 +#define CPU_ID_OMAP3530 0x411fc080 /* TI OMAP3530 */ /* ARM3-specific coprocessor 15 registers */ #define ARM3_CP15_FLUSH 1 Index: sys/arm/cortexa8/omap3/files.omap3 =================================================================== --- sys/arm/cortexa8/omap3/files.omap3 (revision 0) +++ sys/arm/cortexa8/omap3/files.omap3 (revision 0) @@ -0,0 +1,37 @@ +#$FreeBSD$ + +arm/arm/bus_space_generic.c standard +arm/arm/bus_space_asm_generic.S standard +arm/arm/cpufunc_asm_armv5.S standard +arm/arm/cpufunc_asm_arm10.S standard +arm/arm/cpufunc_asm_cortex_a8.S standard +arm/arm/irq_dispatch.S standard + +arm/cortexa8/cortexa8_machdep.c standard +arm/cortexa8/cortexa8_uart.c standard +arm/cortexa8/cortexa8_ttb_debug.c standard + +arm/cortexa8/omap3/omap3.c standard +arm/cortexa8/omap3/omap3_mem.c standard +arm/cortexa8/omap3/omap3_space.c standard +arm/cortexa8/omap3/omap3_space_asm.S standard +arm/cortexa8/omap3/omap3_timer.c standard +arm/cortexa8/omap3/omap3_intr.c standard +arm/cortexa8/omap3/omap3_prcm.c standard +arm/cortexa8/omap3/omap3_scm.c standard +arm/cortexa8/omap3/omap3_dma.c standard +arm/cortexa8/omap3/omap3_gpio.c standard + +arm/cortexa8/omap3/omap3_mmc.c optional omap3_mmc +arm/cortexa8/omap3/omap3_i2c.c optional omap3_i2c + + +arm/cortexa8/omap3/uart_cpu_omap3.c optional uart +arm/cortexa8/omap3/uart_bus_omap3.c optional uart + +dev/uart/uart_dev_ns8250.c optional uart + +# USB Host controller +dev/usb/controller/ehci_omap3.c optional ehci usb + + Index: sys/arm/cortexa8/omap3/omap3_prcm.c =================================================================== --- sys/arm/cortexa8/omap3/omap3_prcm.c (revision 0) +++ sys/arm/cortexa8/omap3/omap3_prcm.c (revision 0) @@ -0,0 +1,422 @@ +/* + * Copyright (c) 2010 + * Ben Gray . + * All rights reserved. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Ben Gray. + * 4. The name of the company nor the name of the author may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY BEN GRAY ``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 BEN GRAY 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. + */ + +/** + * Power, Reset and Clock Managment Module + * + * This is a very simple driver wrapper around the PRCM set of registers in + * the OMAP3 chip. It allows you to turn on and off things like the functional + * and interface clocks to the various on-chip modules. + * + */ +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + + +/** + * Structure that stores the driver context. + * + * This structure is allocated during driver attach, it is not designed to be + * deallocated and a pointer to it is stored globally (g_omap3_prcm_softc). + */ +struct omap3_prcm_softc { + device_t sc_dev; + + /* the bus handle/tag for the clock management (CM) part of the reg set */ + bus_space_tag_t sc_cm_iot; + bus_space_handle_t sc_cm_ioh; + + /* the bus handle/tag for the power & resource management (PRM) part of the + * register set */ + bus_space_tag_t sc_prm_iot; + bus_space_handle_t sc_prm_ioh; + + struct mtx sc_mtx; +}; + +static struct omap3_prcm_softc *g_omap3_prcm_softc = NULL; + +/** + * Macros for driver mutex locking + */ +#define OMAP3_PRCM_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) +#define OMAP3_PRCM_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) +#define OMAP3_PRCM_LOCK_INIT(_sc) \ + mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), \ + "omap3_prcm", MTX_DEF) +#define OMAP3_PRCM_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx); +#define OMAP3_PRCM_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED); +#define OMAP3_PRCM_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED); + + + +/** + * omap3_prcm_setup_dpll5 - probe function for the driver + * @dev: prcm device handle + * + * Simply sets the name of the driver module. + * + * LOCKING: + * None + * + * RETURNS: + * Always returns 0 + */ +static int +omap3_prcm_setup_dpll5(struct omap3_prcm_softc *sc, uint32_t mul, uint32_t div) +{ + uint32_t val; + + /* DPPL5 uses DPLL5_ALWON_FCLK as it's reference clock, this is just SYS_CLK + * which on the beagleboard is 13MHz. + */ + + /* Set the multipler and divider values for the PLL. We want 120Mhz so take + * the system clock (13Mhz) divide by that then multiple by 120. + */ + val = ((120 & 0x7ff) << 8) | ((13 - 1) & 0x7f); + bus_space_write_4(sc->sc_cm_iot, sc->sc_cm_ioh, OMAP35XX_CM_CLKSEL4_PLL, val); + + /* This is the clock divider from the PLL into the 120Mhz clock supplied to + * the USB module. */ + val = 0x01; + bus_space_write_4(sc->sc_cm_iot, sc->sc_cm_ioh, OMAP35XX_CM_CLKSEL5_PLL, val); + + /* PERIPH2_DPLL_FREQSEL = 0x7 (1.75 MHz—2.1 MHz) + * EN_PERIPH2_DPLL = 0x7 (Enables the DPLL5 in lock mode) + */ + val = (7 << 4) | (7 << 0); + bus_space_write_4(sc->sc_cm_iot, sc->sc_cm_ioh, OMAP35XX_CM_CLKEN2_PLL, val); + + + /* Disable auto-idle */ + val = 0x0; + bus_space_write_4(sc->sc_cm_iot, sc->sc_cm_ioh, OMAP35XX_CM_AUTOIDLE2_PLL, val); + + + + /* Wait until the DPLL5 is locked and there is clock activity */ + while (((val = bus_space_read_4(sc->sc_cm_iot, sc->sc_cm_ioh, + OMAP35XX_CM_IDLEST2_CKGEN)) & 0x01) == 0x00) { + printf("OMAP35XX_CM_IDLEST2_PLL = 0x%08x\n", val); + } + + return 0; +} + + +/** + * omap3_prcm_probe - probe function for the driver + * @dev: prcm device handle + * + * Simply sets the name of the driver module. + * + * LOCKING: + * None + * + * RETURNS: + * Always returns 0 + */ +static int +omap3_prcm_probe(device_t dev) +{ + device_set_desc(dev, "TI OMAP3530 Power, Reset and Clock Management"); + return (0); +} + +/** + * omap3_prcm_attach - attach function for the driver + * @dev: prcm device handle + * + * Allocates and sets up the driver context, this simply entails creating a + * bus mappings for the PRCM register set. + * + * LOCKING: + * None + * + * RETURNS: + * Always returns 0 + */ +static int +omap3_prcm_attach(device_t dev) +{ + struct omap3_prcm_softc *sc = device_get_softc(dev); + + g_omap3_prcm_softc = sc; + + sc->sc_dev = dev; + sc->sc_cm_iot = sc->sc_prm_iot = &omap3_bs_tag; + + OMAP3_PRCM_LOCK_INIT(sc); + + /* Map in the clock management register set */ + if (bus_space_map(sc->sc_cm_iot, OMAP35XX_CM_HWBASE, OMAP35XX_CM_SIZE, + 0, &sc->sc_cm_ioh)) { + panic("%s: Cannot map registers", device_get_name(dev)); + } + + /* Map in the power and reset register set */ + if (bus_space_map(sc->sc_prm_iot, OMAP35XX_PRM_HWBASE, OMAP35XX_PRM_SIZE, + 0, &sc->sc_prm_ioh)) { + panic("%s: Cannot map registers", device_get_name(dev)); + } + + printf("[BRG] %s : %d : sc->sc_cm_iot = %p : sc->sc_cm_ioh = 0x%08x\n", + __func__, __LINE__, sc->sc_cm_iot, (uint32_t)sc->sc_cm_ioh); + + + /* Setup DPLL5, this is the 120MHz clock used by the USB module */ + omap3_prcm_setup_dpll5(sc, 120, 12); + + return (0); +} + +static device_method_t g_omap3_prcm_methods[] = { + DEVMETHOD(device_probe, omap3_prcm_probe), + DEVMETHOD(device_attach, omap3_prcm_attach), + {0, 0}, +}; + +static driver_t g_omap3_prcm_driver = { + "omap3_prcm", + g_omap3_prcm_methods, + sizeof(struct omap3_prcm_softc), +}; +static devclass_t g_omap3_prcm_devclass; + +DRIVER_MODULE(omap3_prcm, omap3, g_omap3_prcm_driver, g_omap3_prcm_devclass, 0, 0); +MODULE_VERSION(omap3_prcm, 1); + + + + +/** + * omap3_prcm_disable_clk - disables a clock for a particular module + * @module: identifier for the module to disable, see omap3_prcm.h for a list + * of possible modules. + * Example: OMAP3_MODULE_MMC1_ICLK or OMAP3_MODULE_GPTIMER10_FCLK. + * + * This function can enable either a functional or interface clock, the module + * param defines the clock that is going to be enabled. + * + * LOCKING: + * Internally locks the driver context + * + * RETURNS: + * Always returns 0 + */ +int +omap3_prcm_disable_clk(unsigned int module) +{ + struct omap3_prcm_softc *sc = g_omap3_prcm_softc; + uint32_t val; + uint32_t off; + uint32_t mask; + + if (sc == NULL) { + panic("%s: PRCM module not setup", __func__); + } + + off = OMAP3_MODULE_REG_OFFSET(module); + mask = 1UL << OMAP3_MODULE_REG_BIT(module); + + OMAP3_PRCM_LOCK(sc); + + val = bus_space_read_4(sc->sc_cm_iot, sc->sc_cm_ioh, off); + val &= ~mask; + bus_space_write_4(sc->sc_cm_iot, sc->sc_cm_ioh, off, val); + + OMAP3_PRCM_UNLOCK(sc); + return (0); +} + + +/** + * omap3_prcm_enable_clk - enables a clock for a particular module + * @module: identifier for the module to enable, see omap3_prcm.h for a list + * of possible modules. + * Example: OMAP3_MODULE_MMC1_ICLK or OMAP3_MODULE_GPTIMER10_FCLK. + * + * This function can enable either a functional or interface clock, the module + * param defines the clock that is going to be enabled. + * + * LOCKING: + * Internally locks the driver context + * + * RETURNS: + * Always returns 0 + */ +int +omap3_prcm_enable_clk(unsigned int module) +{ + struct omap3_prcm_softc *sc = g_omap3_prcm_softc; + uint32_t val; + uint32_t off; + uint32_t mask; + + if (sc == NULL) { + panic("%s: PRCM module not setup", __func__); + } + + off = OMAP3_MODULE_REG_OFFSET(module); + mask = 1UL << OMAP3_MODULE_REG_BIT(module); + + OMAP3_PRCM_LOCK(sc); + + val = bus_space_read_4(sc->sc_cm_iot, sc->sc_cm_ioh, off); + val |= mask; + bus_space_write_4(sc->sc_cm_iot, sc->sc_cm_ioh, off, val); + + OMAP3_PRCM_UNLOCK(sc); + + return (0); +} + + + +/** + * omap3_prcm_accessible - checks if a module is accessible + * @module: identifier for the module to check, see omap3_prcm.h for a list + * of possible modules. + * Example: OMAP3_MODULE_MMC1 + * + * + * + * LOCKING: + * Internally locks the driver context + * + * RETURNS: + * Always returns 0 + */ +int +omap3_prcm_accessible(unsigned int module) +{ + struct omap3_prcm_softc *sc = g_omap3_prcm_softc; + uint32_t val; + uint32_t off; + uint32_t mask; + + if (sc == NULL) { + panic("%s: PRCM module not setup", __func__); + } + + off = OMAP3_MODULE_REG_OFFSET(module); + mask = 1UL << OMAP3_MODULE_REG_BIT(module); + + val = bus_space_read_4(sc->sc_cm_iot, sc->sc_cm_ioh, off); + + if (val & mask) { + return 1; + } else { + return 0; + } + +} + + +/** + * omap3_prcm_set_gptimer_clksrc - sets the clock source for a GPTIMER + * @timer: the number of the timer to set the reference clock for + * @sys_clk: if non-zero use the SYSCLK + * + * Currently you can only change the clock source for GPTIMER10 and + * GPTIMER11. + * + * LOCKING: + * Internally locks the driver context + * + * RETURNS: + * 0 on success + * -EINVAL if timer is not 10 or 11 + */ +int +omap3_prcm_set_gptimer_clksrc(int timer, int sys_clk) +{ + struct omap3_prcm_softc *sc = g_omap3_prcm_softc; + uint32_t val; + uint32_t off; + uint32_t mask; + + if (sc == NULL) { + panic("%s: PRCM module not setup", __func__); + } + + switch (timer) { + case 10: + off = OMAP35XX_CM_CLKSEL_CORE; + mask = (1UL << 6); + break; + case 11: + off = OMAP35XX_CM_CLKSEL_CORE; + mask = (1UL << 7); + break; + default: + return (-EINVAL); + } + + OMAP3_PRCM_LOCK(sc); + + val = bus_space_read_4(sc->sc_cm_iot, sc->sc_cm_ioh, off); + if (sys_clk) + val |= mask; + else + val &= ~mask; + bus_space_write_4(sc->sc_cm_iot, sc->sc_cm_ioh, off, val); + + OMAP3_PRCM_UNLOCK(sc); + return (0); +} + + + Index: sys/arm/cortexa8/omap3/omap3_dma.c =================================================================== --- sys/arm/cortexa8/omap3/omap3_dma.c (revision 0) +++ sys/arm/cortexa8/omap3/omap3_dma.c (revision 0) @@ -0,0 +1,1476 @@ +/* + * Copyright (c) 2010 + * Ben Gray . + * All rights reserved. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Ben Gray. + * 4. The name of the company nor the name of the author may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY BEN GRAY ``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 BEN GRAY 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +/** + * Kernel functions for using the DMA controller + * + * + * DMA TRANSFERS: + * A DMA transfer block consists of a number of frames (FN). Each frame + * consists of a number of elements, and each element can have a size of 8, 16, + * or 32 bits. + * + */ + + +/** + * The number of DMA channels possible on the controller. + */ +#define NUM_DMA_CHANNELS 32 + + +/** + * Various register field settings + */ +#define DMA4_CSDP_DATA_TYPE(x) (((x) & 0x3) << 0) +#define DMA4_CSDP_SRC_BURST_MODE(x) (((x) & 0x3) << 7) +#define DMA4_CSDP_DST_BURST_MODE(x) (((x) & 0x3) << 14) +#define DMA4_CSDP_SRC_ENDIANISM(x) (((x) & 0x1) << 21) +#define DMA4_CSDP_DST_ENDIANISM(x) (((x) & 0x1) << 19) +#define DMA4_CSDP_WRITE_MODE(x) (((x) & 0x3) << 16) +#define DMA4_CSDP_SRC_PACKED(x) (((x) & 0x1) << 6) +#define DMA4_CSDP_DST_PACKED(x) (((x) & 0x1) << 13) + +#define DMA4_CCR_DST_ADDRESS_MODE(x) (((x) & 0x3) << 14) +#define DMA4_CCR_SRC_ADDRESS_MODE(x) (((x) & 0x3) << 12) +#define DMA4_CCR_READ_PRIORITY(x) (((x) & 0x1) << 6) +#define DMA4_CCR_WRITE_PRIORITY(x) (((x) & 0x1) << 26) +#define DMA4_CCR_SYNC_TRIGGER(x) ((((x) & 0x60) << 14) \ + | ((x) & 0x1f)) +#define DMA4_CCR_FRAME_SYNC(x) (((x) & 0x1) << 5) +#define DMA4_CCR_BLOCK_SYNC(x) (((x) & 0x1) << 18) +#define DMA4_CCR_SEL_SRC_DST_SYNC(x) (((x) & 0x1) << 24) + +#define DMA4_CCR_PACKET_TRANS (DMA4_CCR_FRAME_SYNC(1) | \ + DMA4_CCR_BLOCK_SYNC(1) ) + +#define DMA4_CSR_DROP (1UL << 1) +#define DMA4_CSR_HALF (1UL << 2) +#define DMA4_CSR_FRAME (1UL << 3) +#define DMA4_CSR_LAST (1UL << 4) +#define DMA4_CSR_BLOCK (1UL << 5) +#define DMA4_CSR_SYNC (1UL << 6) +#define DMA4_CSR_PKT (1UL << 7) +#define DMA4_CSR_TRANS_ERR (1UL << 8) +#define DMA4_CSR_SECURE_ERR (1UL << 9) +#define DMA4_CSR_SUPERVISOR_ERR (1UL << 10) +#define DMA4_CSR_MISALIGNED_ADRS_ERR (1UL << 11) +#define DMA4_CSR_DRAIN_END (1UL << 12) +#define DMA4_CSR_CLEAR_MASK (0xffe) + +#define DMA4_CICR_DROP_IE (1UL << 1) +#define DMA4_CICR_HALF_IE (1UL << 2) +#define DMA4_CICR_FRAME_IE (1UL << 3) +#define DMA4_CICR_LAST_IE (1UL << 4) +#define DMA4_CICR_BLOCK_IE (1UL << 5) +#define DMA4_CICR_PKT_IE (1UL << 7) +#define DMA4_CICR_TRANS_ERR_IE (1UL << 8) +#define DMA4_CICR_SECURE_ERR_IE (1UL << 9) +#define DMA4_CICR_SUPERVISOR_ERR_IE (1UL << 10) +#define DMA4_CICR_MISALIGNED_ADRS_ERR_IE (1UL << 11) +#define DMA4_CICR_DRAIN_IE (1UL << 12) + + + + +/** + * Data structure per DMA channel. + * + * + */ +struct omap3_dma_channel { + + /* The configuration registers for the given channel, these are modified + * by the set functions and only written to the actual registers when a + * transaction is started. + */ + uint32_t reg_csdp; + uint32_t reg_ccr; + uint32_t reg_cicr; + + /* Set when one of the configuration registers above change */ + uint32_t need_reg_write; + + /* Callback function used when an interrupt is tripped on the given channel */ + void (*callback)(unsigned int ch, uint32_t ch_status, void *data); + + /* Callback data passed in the callback ... duh */ + void* callback_data; + +}; + +/** + * DMA driver context, allocated and stored globally, this driver is not + * intetned to ever be unloaded (see g_omap3_dma_sc). + * + */ +struct omap3_dma_softc { + device_t sc_dev; + bus_space_tag_t sc_iotag; + bus_space_handle_t sc_ioh; + struct resource* sc_irq; + + /* I guess in theory we should have a mutex per DMA channel for register + * modifications. But since we know we are never going to be run on a SMP + * system, we can use just the single lock for all channels. + */ + struct mtx sc_mtx; + + /* Bits in the sc_active_channels data field indicate if the channel has + * been activated. + */ + uint32_t sc_active_channels; + + struct omap3_dma_channel + sc_channel[NUM_DMA_CHANNELS]; + +}; + +static struct omap3_dma_softc *g_omap3_dma_sc = NULL; + + +/** + * Function prototypes + * + */ +static void omap3_dma_intr(void *); + + + + +/** + * omap3_dma_readl - reads a 32-bit value from one of the DMA registers + * @sc: DMA device context + * @off: The offset of a register from the DMA register address range + * + * + * RETURNS: + * 32-bit value read from the register. + */ +static inline uint32_t +omap3_dma_readl(struct omap3_dma_softc *sc, bus_size_t off) +{ + return bus_space_read_4(sc->sc_iotag, sc->sc_ioh, off); +} + +/** + * omap3_dma_writel - writes a 32-bit value to one of the DMA registers + * @sc: DMA device context + * @off: The offset of a register from the DMA register address range + * + * + * RETURNS: + * 32-bit value read from the register. + */ +static inline void +omap3_dma_writel(struct omap3_dma_softc *sc, bus_size_t off, uint32_t val) +{ + bus_space_write_4(sc->sc_iotag, sc->sc_ioh, off, val); +} + + + + + + +/** + * omap3_dma_test - test function, to be removed + * + * Simple test function use to verify the DMA behaviour + * + * RETURNS: + * 32-bit value read from the register. + */ +#if 0 +static void +omap3_dma_test(void) +{ + struct omap3_dma_softc *sc = g_omap3_dma_sc; + unsigned int ch; + uint8_t *src; + uint8_t *dst; + vm_paddr_t src_pa; + vm_paddr_t dst_pa; + unsigned int timeout = 0; + uint32_t status = 0; + + src = malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT); + dst = malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT); + + src_pa = pmap_extract(pmap_kernel(), (vm_offset_t)src); + dst_pa = pmap_extract(pmap_kernel(), (vm_offset_t)dst); + + printf("[BRG] %s : %d : src=%p [PA: 0x%08x]\n", __func__, __LINE__, src, src_pa); + printf("[BRG] %s : %d : dst=%p [PA: 0x%08x]\n", __func__, __LINE__, dst, dst_pa); + + + if (omap3_dma_activate_channel(&ch, NULL, NULL) != 0) { + printf("[BRG] %s : %d : omap3_dma_activate_channel failed\n", __func__, __LINE__); + goto err_out; + } + + printf("[BRG] %s : %d : activated channel number %u\n", __func__, __LINE__, ch); + +// if (omap3_dma_sync_params(ch, 0, DMA_SYNC_BLOCK) != 0) { +// printf("[BRG] %s : %d : omap3_dma_sync_params failed\n", __func__, __LINE__); +// goto out; +// } + + + if (omap3_dma_enable_channel_irq(ch, DMA_IRQ_FLAG_BLOCK_COMPL) != 0) { + printf("[BRG] %s : %d : omap3_dma_enable_channel_irq failed\n", __func__, __LINE__); + goto out; + } + + + if (omap3_dma_start_xfer(ch, src_pa, dst_pa, (PAGE_SIZE / 4), 1) != 0) { + printf("[BRG] %s : %d : omap3_dma_start_xfer failed\n", __func__, __LINE__); + goto out; + } + + + + + + while (status == 0 && timeout++ < 10000) { + if (omap3_dma_get_channel_status(ch, &status) != 0) { + printf("[BRG] %s : %d : omap3_dma_get_channel_status failed\n", __func__, __LINE__); + break; + } + + if ((timeout % 10) == 0) { + printf("[BRG] : DMA4_CSAC 0x%08x : DMA4_CDAC 0x%08x : DMA4_CSR 0x%08x\n", + omap3_dma_readl(sc, OMAP35XX_SDMA_CSAC(ch)), + omap3_dma_readl(sc, OMAP35XX_SDMA_CDAC(ch)), + status); + } + } + + printf("[BRG] %s : %d : status 0x%04x : timeout %d\n", __func__, __LINE__, status, timeout); + +out: + if (omap3_dma_deactivate_channel(ch) != 0) { + printf("[BRG] %s : %d : omap3_dma_deactivate_channel failed\n", __func__, __LINE__); + } + +err_out: + free(src, M_DEVBUF); + free(dst, M_DEVBUF); +} +#endif + + +/** + * omap3_dma_dbg_dump_regs - test function, to be removed + * @arg: + * + * + * + * LOCKING: + * DMA registers protected by internal mutex + * + * RETURNS: + * EH_HANDLED or EH_NOT_HANDLED + */ +#if 0 +static void +omap3_dma_dbg_dump_regs(unsigned int ch) +{ + struct omap3_dma_softc *sc = g_omap3_dma_sc; + + /* + "\tDMA4_SYSSTATUS 0x%08x\n" + "\tDMA4_OCP_SYSCONFIG 0x%08x\n" + "\tDMA4_CAPS_0 0x%08x\n" + "\tDMA4_CAPS_2 0x%08x\n" + "\tDMA4_CAPS_3 0x%08x\n" + "\tDMA4_CAPS_4 0x%08x\n" + "\tDMA4_GCR 0x%08x\n" + "\tDMA4_CCR 0x%08x\n" + */ + + printf("DMA register set (channel %u):\n" + "\tDMA4_IRQSTATUS_L 0x%08x 0x%08x 0x%08x 0x%08x\n" + "\tDMA4_IRQENABLE_L 0x%08x 0x%08x 0x%08x 0x%08x\n" + "\tDMA4_CCR 0x%08x\n" + "\tDMA4_CLNK_CTRL 0x%08x\n" + "\tDMA4_CICR 0x%08x\n" + "\tDMA4_CSR 0x%08x\n" + "\tDMA4_CSDP 0x%08x\n" + "\tDMA4_CEN 0x%08x\n" + "\tDMA4_CFN 0x%08x\n" + "\tDMA4_CSSA 0x%08x\n" + "\tDMA4_CDSA 0x%08x\n" + "\tDMA4_CSE 0x%08x\n" + "\tDMA4_CSF 0x%08x\n" + "\tDMA4_CDE 0x%08x\n" + "\tDMA4_CDF 0x%08x\n" + "\tDMA4_CSAC 0x%08x\n" + "\tDMA4_CDAC 0x%08x\n" + "\tDMA4_CCEN 0x%08x\n" + "\tDMA4_CCFN 0x%08x\n" + "\tDMA4_COLOR 0x%08x\n", + ch, + omap3_dma_readl(sc, OMAP35XX_SDMA_IRQSTATUS_L(0)), + omap3_dma_readl(sc, OMAP35XX_SDMA_IRQSTATUS_L(1)), + omap3_dma_readl(sc, OMAP35XX_SDMA_IRQSTATUS_L(2)), + omap3_dma_readl(sc, OMAP35XX_SDMA_IRQSTATUS_L(3)), + omap3_dma_readl(sc, OMAP35XX_SDMA_IRQENABLE_L(0)), + omap3_dma_readl(sc, OMAP35XX_SDMA_IRQENABLE_L(1)), + omap3_dma_readl(sc, OMAP35XX_SDMA_IRQENABLE_L(2)), + omap3_dma_readl(sc, OMAP35XX_SDMA_IRQENABLE_L(3)), + omap3_dma_readl(sc, OMAP35XX_SDMA_CCR(ch)), + omap3_dma_readl(sc, OMAP35XX_SDMA_CLNK_CTRL(ch)), + omap3_dma_readl(sc, OMAP35XX_SDMA_CICR(ch)), + omap3_dma_readl(sc, OMAP35XX_SDMA_CSR(ch)), + omap3_dma_readl(sc, OMAP35XX_SDMA_CSDP(ch)), + omap3_dma_readl(sc, OMAP35XX_SDMA_CEN(ch)), + omap3_dma_readl(sc, OMAP35XX_SDMA_CFN(ch)), + omap3_dma_readl(sc, OMAP35XX_SDMA_CSSA(ch)), + omap3_dma_readl(sc, OMAP35XX_SDMA_CDSA(ch)), + omap3_dma_readl(sc, OMAP35XX_SDMA_CSE(ch)), + omap3_dma_readl(sc, OMAP35XX_SDMA_CSF(ch)), + omap3_dma_readl(sc, OMAP35XX_SDMA_CDE(ch)), + omap3_dma_readl(sc, OMAP35XX_SDMA_CDF(ch)), + omap3_dma_readl(sc, OMAP35XX_SDMA_CSAC(ch)), + omap3_dma_readl(sc, OMAP35XX_SDMA_CDAC(ch)), + omap3_dma_readl(sc, OMAP35XX_SDMA_CCEN(ch)), + omap3_dma_readl(sc, OMAP35XX_SDMA_CCFN(ch)), + omap3_dma_readl(sc, OMAP35XX_SDMA_COLOR(ch)) + ); + +} +#endif + + + + +/** + * omap3_dma_probe - driver probe function + * @dev: dma device handle + * + * + * + * RETURNS: + * Always returns 0. + */ +static int +omap3_dma_probe(device_t dev) +{ + + device_set_desc(dev, "TI OMAP3 DMA Controller"); + return (0); +} + + +/** + * omap3_dma_attach - driver attach function + * @dev: dma device handle + * + * Initialises memory mapping/pointers to the DMA register set and requests + * IRQs. This is effectively the setup function for the driver. + * + * RETURNS: + * 0 on success or a negative error code failure. + */ +static int +omap3_dma_attach(device_t dev) +{ + struct omap3_dma_softc *sc = device_get_softc(dev); + unsigned int i = 0; + uint32_t val; + int rid = 0; + void *ihl; + int err; + + + /* Setup the basics */ + sc->sc_dev = dev; + sc->sc_iotag = &omap3_bs_tag; + + /* No channels active at the moment */ + sc->sc_active_channels = 0x00000000; + + + /* Mutex to protect the shared data structures */ + mtx_init(&sc->sc_mtx, device_get_nameunit(dev), "omap3_dma", MTX_SPIN); + + /* Map in the DMA controller register set */ + if (bus_space_map(sc->sc_iotag, OMAP35XX_SDMA_HWBASE, OMAP35XX_SDMA_SIZE, 0, + &sc->sc_ioh)) { + panic("%s: Cannot map registers", device_get_name(dev)); + } + + + /* For the DMA module there are no interface or functional clocks that need + * to be turned on ... I think. + */ + + /* Setup configuration */ + val = omap3_dma_readl(sc, OMAP35XX_SDMA_GCR); + + /* Disable all interrupts */ + for (i=0; i<4; i++) { + omap3_dma_writel(sc, OMAP35XX_SDMA_IRQENABLE_L(i), + 0x00000000); + } + + /* Do a soft-reset */ + omap3_dma_writel(sc, OMAP35XX_SDMA_OCP_SYSCONFIG, 0x0002); + /* TODO: Add a timeout */ + while ((omap3_dma_readl(sc, OMAP35XX_SDMA_SYSSTATUS) & 0x1) == 0x0) + continue; + + + /* Install interrupt handlers for the for possible interrupts. Any channel + * can trip one of the four IRQs + */ + sc->sc_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, OMAP35XX_IRQ_SDMA0, + OMAP35XX_IRQ_SDMA3, 4, RF_ACTIVE); + if (sc->sc_irq == NULL) + panic("Unable to setup the clock irq handler.\n"); + + err = bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_MISC | INTR_MPSAFE, NULL, + omap3_dma_intr, NULL, &ihl); + if (err) { + panic("%s: Cannot register IRQ", device_get_name(dev)); + } + + + + /* Store the DMA structure globally ... this driver should never be unloaded */ + g_omap3_dma_sc = sc; + + + /* DEBUG : omap3_dma_test(); */ + + + return (0); +} + + +static device_method_t g_omap3_dma_methods[] = { + DEVMETHOD(device_probe, omap3_dma_probe), + DEVMETHOD(device_attach, omap3_dma_attach), + {0, 0}, +}; + +static driver_t g_omap3_dma_driver = { + "omap3_dma", + g_omap3_dma_methods, + sizeof(struct omap3_dma_softc), +}; +static devclass_t g_omap3_dma_devclass; + +DRIVER_MODULE(omap3_dma, omap3, g_omap3_dma_driver, g_omap3_dma_devclass, 0, 0); +MODULE_DEPEND(omap3_dma, omap3_prcm, 1, 1, 1); + + + + + +/** + * omap3_dma_intr - interrupt handler for all 4 DMA IRQs + * @arg: ignored + * + * Called when any of the four DMA IRQs are triggered. + * + * LOCKING: + * DMA registers protected by internal mutex + * + * RETURNS: + * nothing + */ +static void +omap3_dma_intr(void *arg) +{ + struct omap3_dma_softc *sc = g_omap3_dma_sc; + uint32_t intr; + uint32_t csr; + unsigned int ch, j; + struct omap3_dma_channel* channel; + + mtx_lock(&sc->sc_mtx); + + for (j=0; j<4; j++) { + + /* Get the flag interrupts (enabled) */ + intr = omap3_dma_readl(sc,OMAP35XX_SDMA_IRQSTATUS_L(j)); + intr &= omap3_dma_readl(sc,OMAP35XX_SDMA_IRQENABLE_L(j)); + if (intr == 0x00000000) + continue; + + + /* Loop through checking the status bits */ + for (ch=0; ch<32; ch++) { + if (intr & (1 << ch)) { + channel = &sc->sc_channel[ch]; + + /* Read the CSR regsiter and verify we don't have a spurious IRQ */ + csr = omap3_dma_readl(sc, OMAP35XX_SDMA_CSR(ch)); + if (csr == 0) { + printf("Spurious DMA IRQ for channel %d\n", ch); + continue; + } + + /* Sanity check this channel is active */ + if ((sc->sc_active_channels & (1 << ch)) == 0) { + printf("IRQ %d for a non-activated channel %d\n", + j, ch); + continue; + } + + /* Check the status error codes */ + if (csr & DMA4_CSR_DROP) + printf("Synchronization event drop occurred during the" + "transfer on channel %u", ch); + if (csr & DMA4_CSR_SECURE_ERR) + printf("Secure transaction error event on channel %u", ch); + if (csr & DMA4_CSR_MISALIGNED_ADRS_ERR) + printf("Misaligned address error event on channel %u", ch); + if (csr & DMA4_CSR_TRANS_ERR) { + printf("Transaction error event on channel %u", ch); + /* Apparently according to linux code, there is an errata + * that says the channel is not disabled upon this error. + * They explicitly disable the channel here .. since I + * haven't seen the errata, I'm going to ignore for now. + */ + } + + /* Clear the status flags for the IRQ */ + omap3_dma_writel(sc, OMAP35XX_SDMA_CSR(ch), DMA4_CSR_CLEAR_MASK); + omap3_dma_writel(sc, OMAP35XX_SDMA_IRQSTATUS_L(j), (1 << ch)); + + /* Call the callback for the given channel */ + if (channel->callback) + channel->callback(ch, csr, channel->callback_data); + + } + } + } + + mtx_unlock(&sc->sc_mtx); + + return; +} + + + +/** + * omap3_dma_activate_channel - activates a DMA channel + * @ch: upon return contains the channel allocated + * @callback: a callback function to associate with the channel + * @data: optional data supplied when the callback is called + * + * Simply activates a channel be enabling and writing default values to the + * channels register set. It doesn't start a transaction, just populates the + * internal data structures and sets defaults for the register set. + * + * Note this function doesn't enable interrupts, for that you need to call + * omap3_dma_enable_channel_irq(). If not using IRQ to detect the end of the + * transfer, you can use omap3_dma_status_poll() to detect a change in the + * status. + * + * A channel must be activated before any of the other DMA functions can be + * called on it. + * + * LOCKING: + * DMA registers protected by internal mutex + * + * RETURNS: + * 0 on success, otherwise an error code + */ +int +omap3_dma_activate_channel(unsigned int *ch, + void (*callback)(unsigned int ch, uint32_t status, void *data), + void *data) +{ + struct omap3_dma_softc *sc = g_omap3_dma_sc; + struct omap3_dma_channel *channel = NULL; + uint32_t adr; + + /* Sanity check */ + if (sc == NULL) + return (ENOMEM); + if (ch == NULL) + return (EINVAL); + + mtx_lock(&sc->sc_mtx); + + /* Check to see if all channels are in use */ + if (sc->sc_active_channels == 0xffffffff) { + mtx_unlock(&sc->sc_mtx); + return (ENOMEM); + } + + /* Find the first non-active channel */ + *ch = ffs(sc->sc_active_channels); + + /* Mark the channel as active */ + sc->sc_active_channels |= (1 << *ch); + + + + /* Get the channel struct and populate the fields */ + channel = &sc->sc_channel[*ch]; + + channel->callback = callback; + channel->callback_data = data; + + channel->need_reg_write = 1; + + /* Set the default configuration for the DMA channel */ + channel->reg_csdp = DMA4_CSDP_DATA_TYPE(0x2) + | DMA4_CSDP_SRC_BURST_MODE(0) + | DMA4_CSDP_DST_BURST_MODE(0) + | DMA4_CSDP_SRC_ENDIANISM(0) + | DMA4_CSDP_DST_ENDIANISM(0) + | DMA4_CSDP_WRITE_MODE(0) + | DMA4_CSDP_SRC_PACKED(0) + | DMA4_CSDP_DST_PACKED(0); + + channel->reg_ccr = DMA4_CCR_DST_ADDRESS_MODE(1) + | DMA4_CCR_SRC_ADDRESS_MODE(1) + | DMA4_CCR_READ_PRIORITY(0) + | DMA4_CCR_WRITE_PRIORITY(0) + | DMA4_CCR_SYNC_TRIGGER(0) + | DMA4_CCR_FRAME_SYNC(0) + | DMA4_CCR_BLOCK_SYNC(0); + + channel->reg_cicr = DMA4_CICR_TRANS_ERR_IE + | DMA4_CICR_SECURE_ERR_IE + | DMA4_CICR_SUPERVISOR_ERR_IE + | DMA4_CICR_MISALIGNED_ADRS_ERR_IE; + + + + /* Clear all the channel registers, this should abort any transaction */ + for (adr = OMAP35XX_SDMA_CCR(*ch); adr <= OMAP35XX_SDMA_COLOR(*ch); adr += 4) + omap3_dma_writel(sc, adr, 0x00000000); + + mtx_unlock(&sc->sc_mtx); + + return 0; +} + + +/** + * omap3_dma_deactivate_channel - deactivates a channel + * @ch: the channel to deactivate + * + * + * + * LOCKING: + * DMA registers protected by internal mutex + * + * RETURNS: + * EH_HANDLED or EH_NOT_HANDLED + */ +int +omap3_dma_deactivate_channel(unsigned int ch) +{ + struct omap3_dma_softc *sc = g_omap3_dma_sc; + unsigned int j; + unsigned int adr; + + /* Sanity check */ + if (sc == NULL) + return (ENOMEM); + + + mtx_lock(&sc->sc_mtx); + + /* First check if the channel is currently active */ + if ((sc->sc_active_channels & (1 << ch)) == 0) { + mtx_unlock(&sc->sc_mtx); + return (EBUSY); + } + + /* Mark the channel as inactive */ + sc->sc_active_channels &= ~(1 << ch); + + + /* Disable all DMA interrupts for the channel. */ + omap3_dma_writel(sc, OMAP35XX_SDMA_CICR(ch), 0); + + /* Make sure the DMA transfer is stopped. */ + omap3_dma_writel(sc, OMAP35XX_SDMA_CCR(ch), 0); + + + /* Clear the CSR register and IRQ status register */ + omap3_dma_writel(sc, OMAP35XX_SDMA_CSR(ch), DMA4_CSR_CLEAR_MASK); + for (j=0; j<4; j++) { + omap3_dma_writel(sc, OMAP35XX_SDMA_IRQSTATUS_L(j), (1 << ch)); + } + + + + /* Clear all the channel registers, this should abort any transaction */ + for (adr = OMAP35XX_SDMA_CCR(ch); adr <= OMAP35XX_SDMA_COLOR(ch); adr += 4) + omap3_dma_writel(sc, adr, 0x00000000); + + + mtx_unlock(&sc->sc_mtx); + + return 0; +} + + +/** + * omap3_dma_disable_channel_irq - disables IRQ's on the given channel + * @ch: the channel to disable IRQ's on + * + * Disable interupt generation for the given channel. + * + * LOCKING: + * DMA registers protected by internal mutex + * + * RETURNS: + * EH_HANDLED or EH_NOT_HANDLED + */ +int +omap3_dma_disable_channel_irq(unsigned int ch) +{ + struct omap3_dma_softc *sc = g_omap3_dma_sc; + uint32_t irq_enable; + unsigned int j; + + /* Sanity check */ + if (sc == NULL) + return (ENOMEM); + + mtx_lock(&sc->sc_mtx); + + if ((sc->sc_active_channels & (1 << ch)) == 0) { + mtx_unlock(&sc->sc_mtx); + return (EINVAL); + } + + /* Disable all the individual error conditions */ + sc->sc_channel[ch].reg_cicr = 0x0000; + omap3_dma_writel(sc, OMAP35XX_SDMA_CICR(ch), 0x0000); + + /* Disable the channel interrupt enable */ + for (j=0; j<4; j++) { + irq_enable = omap3_dma_readl(sc, OMAP35XX_SDMA_IRQENABLE_L(j)); + irq_enable &= ~(1 << ch); + + omap3_dma_writel(sc, OMAP35XX_SDMA_IRQENABLE_L(j), irq_enable); + } + + /* Indicate the registers need to be rewritten on the next transaction */ + sc->sc_channel[ch].need_reg_write = 1; + + mtx_unlock(&sc->sc_mtx); + + return (0); +} + +/** + * omap3_dma_disable_channel_irq - enables IRQ's on the given channel + * @ch: the channel to enable IRQ's on + * @flags: bitmask of interrupt types to enable + * + * Flags can be a bitmask of the following options: + * DMA_IRQ_FLAG_DROP + * DMA_IRQ_FLAG_HALF_FRAME_COMPL + * DMA_IRQ_FLAG_FRAME_COMPL + * DMA_IRQ_FLAG_START_LAST_FRAME + * DMA_IRQ_FLAG_BLOCK_COMPL + * DMA_IRQ_FLAG_ENDOF_PKT + * DMA_IRQ_FLAG_DRAIN + * + * + * LOCKING: + * DMA registers protected by internal mutex + * + * RETURNS: + * EH_HANDLED or EH_NOT_HANDLED + */ +int +omap3_dma_enable_channel_irq(unsigned int ch, uint32_t flags) +{ + struct omap3_dma_softc *sc = g_omap3_dma_sc; + uint32_t irq_enable; + + /* Sanity check */ + if (sc == NULL) + return (ENOMEM); + + mtx_lock(&sc->sc_mtx); + + if ((sc->sc_active_channels & (1 << ch)) == 0) { + mtx_unlock(&sc->sc_mtx); + return (EINVAL); + } + + /* Always enable the error interrupts if we have interrupts enabled */ + flags |= DMA4_CICR_TRANS_ERR_IE | DMA4_CICR_SECURE_ERR_IE | + DMA4_CICR_SUPERVISOR_ERR_IE | DMA4_CICR_MISALIGNED_ADRS_ERR_IE; + + sc->sc_channel[ch].reg_cicr = flags; + + /* Write the values to the register */ + omap3_dma_writel(sc, OMAP35XX_SDMA_CICR(ch), flags); + + + /* Enable the channel interrupt enable */ + irq_enable = omap3_dma_readl(sc, OMAP35XX_SDMA_IRQENABLE_L(0)); + irq_enable |= (1 << ch); + + omap3_dma_writel(sc, OMAP35XX_SDMA_IRQENABLE_L(0), irq_enable); + + + /* Indicate the registers need to be rewritten on the next transaction */ + sc->sc_channel[ch].need_reg_write = 1; + + mtx_unlock(&sc->sc_mtx); + + return (0); +} + + +/** + * omap3_dma_get_channel_status - returns the status of a given channel + * @ch: the channel number to get the status of + * @status: upon return will contain the status bitmask, see below for possible + * values. + * + * DMA_STATUS_DROP + * DMA_STATUS_HALF + * DMA_STATUS_FRAME + * DMA_STATUS_LAST + * DMA_STATUS_BLOCK + * DMA_STATUS_SYNC + * DMA_STATUS_PKT + * DMA_STATUS_TRANS_ERR + * DMA_STATUS_SECURE_ERR + * DMA_STATUS_SUPERVISOR_ERR + * DMA_STATUS_MISALIGNED_ADRS_ERR + * DMA_STATUS_DRAIN_END + * + * + * LOCKING: + * DMA registers protected by internal mutex + * + * RETURNS: + * EH_HANDLED or EH_NOT_HANDLED + */ +int +omap3_dma_get_channel_status(unsigned int ch, uint32_t *status) +{ + struct omap3_dma_softc *sc = g_omap3_dma_sc; + uint32_t csr; + + /* Sanity check */ + if (sc == NULL) + return (ENOMEM); + + mtx_lock(&sc->sc_mtx); + + if ((sc->sc_active_channels & (1 << ch)) == 0) { + mtx_unlock(&sc->sc_mtx); + return (EINVAL); + } + + mtx_unlock(&sc->sc_mtx); + + csr = omap3_dma_readl(sc, OMAP35XX_SDMA_CSR(ch)); + + if (status != NULL) + *status = csr; + + return (0); +} + + +/** + * omap3_dma_start_xfer - starts a DMA transfer + * @ch: the channel number to set the endianess of + * @src_paddr: the source phsyical address + * @dst_paddr: the destination phsyical address + * @elmcnt: the number of elements in a frame, an element is either an 8, 16 + * or 32-bit value as defined by omap3_dma_set_xfer_burst() + * @frmcnt: the number of frames per block + * + * + * LOCKING: + * DMA registers protected by internal mutex + * + * RETURNS: + * EH_HANDLED or EH_NOT_HANDLED + */ +int +omap3_dma_start_xfer(unsigned int ch, unsigned int src_paddr, + unsigned long dst_paddr, + unsigned int frmcnt, unsigned int elmcnt) +{ + struct omap3_dma_softc *sc = g_omap3_dma_sc; + struct omap3_dma_channel *channel; + uint32_t ccr; + + /* Sanity check */ + if (sc == NULL) + return (ENOMEM); + + mtx_lock(&sc->sc_mtx); + + if ((sc->sc_active_channels & (1 << ch)) == 0) { + mtx_unlock(&sc->sc_mtx); + return (EINVAL); + } + + channel = &sc->sc_channel[ch]; + + /* a) Write the CSDP register */ + //if (channel->need_reg_write) + omap3_dma_writel(sc, OMAP35XX_SDMA_CSDP(ch), + channel->reg_csdp | DMA4_CSDP_WRITE_MODE(1)); + + + /* b) Set the number of element per frame CEN[23:0] */ + omap3_dma_writel(sc, OMAP35XX_SDMA_CEN(ch), elmcnt); + + /* c) Set the number of frame per block CFN[15:0] */ + omap3_dma_writel(sc, OMAP35XX_SDMA_CFN(ch), frmcnt); + + /* d) Set the Source/dest start address index CSSA[31:0]/CDSA[31:0] */ + omap3_dma_writel(sc, OMAP35XX_SDMA_CSSA(ch), src_paddr); + omap3_dma_writel(sc, OMAP35XX_SDMA_CDSA(ch), dst_paddr); + + + /* e) Write the CCR register */ + //if (channel->need_reg_write) + omap3_dma_writel(sc, OMAP35XX_SDMA_CCR(ch), channel->reg_ccr); + + + /* f) - Set the source element index increment CSEI[15:0] */ + omap3_dma_writel(sc, OMAP35XX_SDMA_CSE(ch), 0x0001); + + /* - Set the source frame index increment CSFI[15:0] */ + omap3_dma_writel(sc, OMAP35XX_SDMA_CSF(ch), 0x0001); + + /* - Set the destination element index increment CDEI[15:0]*/ + omap3_dma_writel(sc, OMAP35XX_SDMA_CDE(ch), 0x0001); + + /* - Set the destination frame index increment CDFI[31:0] */ + omap3_dma_writel(sc, OMAP35XX_SDMA_CDF(ch), 0x0001); + + + + /* Clear the status register */ + omap3_dma_writel(sc, OMAP35XX_SDMA_CSR(ch), 0x1FFE); + + /* DEBUG: omap3_dma_dbg_dump_regs(ch); */ + + /* Write the start-bit and away we go */ + ccr = omap3_dma_readl(sc, OMAP35XX_SDMA_CCR(ch)); + ccr |= (1 << 7); + omap3_dma_writel(sc, OMAP35XX_SDMA_CCR(ch), ccr); + + + /* Clear the reg write flag */ + channel->need_reg_write = 0; + + mtx_unlock(&sc->sc_mtx); + + return (0); +} + + +/** + * omap3_dma_start_xfer_packet - starts a packet DMA transfer + * @ch: the channel number to use for the transfer + * @src_paddr: the source physical address + * @dst_paddr: the destination physical address + * @frmcnt: the number of frames to transfer + * @elmcnt: the number of elements in a frame, an element is either an 8, 16 + * or 32-bit value as defined by omap3_dma_set_xfer_burst() + * @pktsize: the number of elements in each transfer packet + * + * The @frmcnt and @elmcnt define the overall number of bytes to transfer, + * typically @frmcnt is 1 and @elmcnt contains the total number of elements. + * @pktsize is the size of each individual packet, there might be multiple + * packets per transfer. i.e. for the following with element size of 32-bits + * + * frmcnt = 1, elmcnt = 512, pktsize = 128 + * + * Total transfer bytes = 1 * 512 = 512 elements or 2048 bytes + * Packets transfered = 128 / 512 = 4 + * + * + * LOCKING: + * DMA registers protected by internal mutex + * + * RETURNS: + * EH_HANDLED or EH_NOT_HANDLED + */ +int +omap3_dma_start_xfer_packet(unsigned int ch, unsigned int src_paddr, + unsigned long dst_paddr, unsigned int frmcnt, + unsigned int elmcnt, unsigned int pktsize) +{ + struct omap3_dma_softc *sc = g_omap3_dma_sc; + struct omap3_dma_channel *channel; + uint32_t ccr; + + /* Sanity check */ + if (sc == NULL) + return (ENOMEM); + + mtx_lock(&sc->sc_mtx); + + if ((sc->sc_active_channels & (1 << ch)) == 0) { + mtx_unlock(&sc->sc_mtx); + return (EINVAL); + } + + channel = &sc->sc_channel[ch]; + + /* a) Write the CSDP register */ + if (channel->need_reg_write) + omap3_dma_writel(sc, OMAP35XX_SDMA_CSDP(ch), + channel->reg_csdp | DMA4_CSDP_WRITE_MODE(1)); + + + /* b) Set the number of elements to transfer CEN[23:0] */ + omap3_dma_writel(sc, OMAP35XX_SDMA_CEN(ch), elmcnt); + + /* c) Set the number of frames to transfer CFN[15:0] */ + omap3_dma_writel(sc, OMAP35XX_SDMA_CFN(ch), frmcnt); + + /* d) Set the Source/dest start address index CSSA[31:0]/CDSA[31:0] */ + omap3_dma_writel(sc, OMAP35XX_SDMA_CSSA(ch), src_paddr); + omap3_dma_writel(sc, OMAP35XX_SDMA_CDSA(ch), dst_paddr); + + + /* e) Write the CCR register */ + omap3_dma_writel(sc, OMAP35XX_SDMA_CCR(ch), + channel->reg_ccr | DMA4_CCR_PACKET_TRANS); + + /* f) - Set the source element index increment CSEI[15:0] */ + omap3_dma_writel(sc, OMAP35XX_SDMA_CSE(ch), 0x0001); + + /* - Set the packet size, this is dependent on the sync source */ + if (channel->reg_ccr & DMA4_CCR_SEL_SRC_DST_SYNC(1)) + omap3_dma_writel(sc, OMAP35XX_SDMA_CSF(ch), pktsize); + else + omap3_dma_writel(sc, OMAP35XX_SDMA_CDE(ch), pktsize); + + /* - Set the destination frame index increment CDFI[31:0] */ + omap3_dma_writel(sc, OMAP35XX_SDMA_CDF(ch), 0x0001); + + + + /* Clear the status register */ + omap3_dma_writel(sc, OMAP35XX_SDMA_CSR(ch), 0x1FFE); + + /* DEBUG omap3_dma_dbg_dump_regs(ch); */ + + /* Write the start-bit and away we go */ + ccr = omap3_dma_readl(sc, OMAP35XX_SDMA_CCR(ch)); + ccr |= (1 << 7); + omap3_dma_writel(sc, OMAP35XX_SDMA_CCR(ch), ccr); + + + /* Clear the reg write flag */ + channel->need_reg_write = 0; + + mtx_unlock(&sc->sc_mtx); + + return (0); +} + + +/** + * omap3_dma_stop_xfer - stops any currently active transfers + * @ch: the channel number to set the endianess of + * + * This function call is effectively a NOP if no transaction is in progress. + * + * LOCKING: + * DMA registers protected by internal mutex + * + * RETURNS: + * EH_HANDLED or EH_NOT_HANDLED + */ +int +omap3_dma_stop_xfer(unsigned int ch) +{ + struct omap3_dma_softc *sc = g_omap3_dma_sc; + unsigned int j; + + /* Sanity check */ + if (sc == NULL) + return (ENOMEM); + + mtx_lock(&sc->sc_mtx); + + if ((sc->sc_active_channels & (1 << ch)) == 0) { + mtx_unlock(&sc->sc_mtx); + return (EINVAL); + } + + + /* Disable all DMA interrupts for the channel. */ + omap3_dma_writel(sc, OMAP35XX_SDMA_CICR(ch), 0); + + /* Make sure the DMA transfer is stopped. */ + omap3_dma_writel(sc, OMAP35XX_SDMA_CCR(ch), 0); + + + /* Clear the CSR register and IRQ status register */ + omap3_dma_writel(sc, OMAP35XX_SDMA_CSR(ch), DMA4_CSR_CLEAR_MASK); + for (j=0; j<4; j++) { + omap3_dma_writel(sc, OMAP35XX_SDMA_IRQSTATUS_L(j), (1 << ch)); + } + + /* Configuration registers need to be re-written on the next xfer */ + sc->sc_channel[ch].need_reg_write = 1; + + mtx_unlock(&sc->sc_mtx); + + return (0); +} + + +/** + * omap3_dma_set_xfer_endianess - sets the endianess of subsequent transfers + * @ch: the channel number to set the endianess of + * @src: the source endianess (either DMA_ENDIAN_LITTLE or DMA_ENDIAN_BIG) + * @dst: the destination endianess (either DMA_ENDIAN_LITTLE or DMA_ENDIAN_BIG) + * + * + * LOCKING: + * DMA registers protected by internal mutex + * + * RETURNS: + * EH_HANDLED or EH_NOT_HANDLED + */ +int +omap3_dma_set_xfer_endianess(unsigned int ch, unsigned int src, unsigned int dst) +{ + struct omap3_dma_softc *sc = g_omap3_dma_sc; + + /* Sanity check */ + if (sc == NULL) + return (ENOMEM); + + mtx_lock(&sc->sc_mtx); + + if ((sc->sc_active_channels & (1 << ch)) == 0) { + mtx_unlock(&sc->sc_mtx); + return (EINVAL); + } + + sc->sc_channel[ch].reg_csdp &= ~DMA4_CSDP_SRC_ENDIANISM(1); + sc->sc_channel[ch].reg_csdp |= DMA4_CSDP_SRC_ENDIANISM(src); + + sc->sc_channel[ch].reg_csdp &= ~DMA4_CSDP_DST_ENDIANISM(1); + sc->sc_channel[ch].reg_csdp |= DMA4_CSDP_DST_ENDIANISM(dst); + + sc->sc_channel[ch].need_reg_write = 1; + + mtx_unlock(&sc->sc_mtx); + + return 0; +} + + +/** + * omap3_dma_set_xfer_burst - sets the source and destination element size + * @ch: the channel number to set the burst settings of + * @src: the source endianess (either DMA_BURST_NONE, DMA_BURST_16, DMA_BURST_32 + * or DMA_BURST_64) + * @dst: the destination endianess (either DMA_BURST_NONE, DMA_BURST_16, + * DMA_BURST_32 or DMA_BURST_64) + * + * This function sets the size of the elements for all subsequent transfers. + * + * LOCKING: + * DMA registers protected by internal mutex + * + * RETURNS: + * EH_HANDLED or EH_NOT_HANDLED + */ +int +omap3_dma_set_xfer_burst(unsigned int ch, unsigned int src, unsigned int dst) +{ + struct omap3_dma_softc *sc = g_omap3_dma_sc; + + /* Sanity check */ + if (sc == NULL) + return (ENOMEM); + + mtx_lock(&sc->sc_mtx); + + if ((sc->sc_active_channels & (1 << ch)) == 0) { + mtx_unlock(&sc->sc_mtx); + return (EINVAL); + } + + sc->sc_channel[ch].reg_csdp &= ~DMA4_CSDP_SRC_BURST_MODE(0x3); + sc->sc_channel[ch].reg_csdp |= DMA4_CSDP_SRC_BURST_MODE(src); + + sc->sc_channel[ch].reg_csdp &= ~DMA4_CSDP_DST_BURST_MODE(0x3); + sc->sc_channel[ch].reg_csdp |= DMA4_CSDP_DST_BURST_MODE(dst); + + sc->sc_channel[ch].need_reg_write = 1; + + mtx_unlock(&sc->sc_mtx); + + return 0; +} + + +/** + * omap3_dma_set_xfer_data_type - driver attach function + * @ch: the channel number to set the endianess of + * @type: the xfer data type (either DMA_DATA_8BITS_SCALAR, DMA_DATA_16BITS_SCALAR + * or DMA_DATA_32BITS_SCALAR) + * + * + * LOCKING: + * DMA registers protected by internal mutex + * + * RETURNS: + * EH_HANDLED or EH_NOT_HANDLED + */ +int +omap3_dma_set_xfer_data_type(unsigned int ch, unsigned int type) +{ + struct omap3_dma_softc *sc = g_omap3_dma_sc; + + /* Sanity check */ + if (sc == NULL) + return (ENOMEM); + + mtx_lock(&sc->sc_mtx); + + if ((sc->sc_active_channels & (1 << ch)) == 0) { + mtx_unlock(&sc->sc_mtx); + return (EINVAL); + } + + sc->sc_channel[ch].reg_csdp &= ~DMA4_CSDP_DATA_TYPE(0x3); + sc->sc_channel[ch].reg_csdp |= DMA4_CSDP_DATA_TYPE(type); + + sc->sc_channel[ch].need_reg_write = 1; + + mtx_unlock(&sc->sc_mtx); + + return 0; +} + + +/** + * omap3_dma_set_callback - driver attach function + * @dev: dma device handle + * + * + * + * LOCKING: + * DMA registers protected by internal mutex + * + * RETURNS: + * EH_HANDLED or EH_NOT_HANDLED + */ +int +omap3_dma_set_callback(unsigned int ch, + void (*callback)(unsigned int ch, uint32_t status, void *data), + void *data) +{ + struct omap3_dma_softc *sc = g_omap3_dma_sc; + + /* Sanity check */ + if (sc == NULL) + return (ENOMEM); + + mtx_lock(&sc->sc_mtx); + + if ((sc->sc_active_channels & (1 << ch)) == 0) { + mtx_unlock(&sc->sc_mtx); + return (EINVAL); + } + + sc->sc_channel[ch].callback = callback; + sc->sc_channel[ch].callback_data = data; + + sc->sc_channel[ch].need_reg_write = 1; + + mtx_unlock(&sc->sc_mtx); + + return 0; +} + + +/** + * omap3_dma_set_callback - driver attach function + * @dev: dma device handle + * + * + * + * LOCKING: + * DMA registers protected by internal mutex + * + * RETURNS: + * EH_HANDLED or EH_NOT_HANDLED + */ +int +omap3_dma_sync_params(unsigned int ch, unsigned int trigger, unsigned int mode) +{ + struct omap3_dma_softc *sc = g_omap3_dma_sc; + uint32_t ccr; + + /* Sanity check */ + if (sc == NULL) + return (ENOMEM); + + mtx_lock(&sc->sc_mtx); + + if ((sc->sc_active_channels & (1 << ch)) == 0) { + mtx_unlock(&sc->sc_mtx); + return (EINVAL); + } + + ccr = sc->sc_channel[ch].reg_ccr; + + ccr &= ~DMA4_CCR_SYNC_TRIGGER(0x7F); + ccr |= DMA4_CCR_SYNC_TRIGGER(trigger + 1); + + if (mode & DMA_SYNC_FRAME) + ccr |= DMA4_CCR_FRAME_SYNC(1); + else + ccr &= ~DMA4_CCR_FRAME_SYNC(1); + + if (mode & DMA_SYNC_BLOCK) + ccr |= DMA4_CCR_BLOCK_SYNC(1); + else + ccr &= ~DMA4_CCR_BLOCK_SYNC(1); + + if (mode & DMA_SYNC_TRIG_ON_SRC) + ccr |= DMA4_CCR_SEL_SRC_DST_SYNC(1); + else + ccr &= ~DMA4_CCR_SEL_SRC_DST_SYNC(1); + + sc->sc_channel[ch].reg_ccr = ccr; + + sc->sc_channel[ch].need_reg_write = 1; + + mtx_unlock(&sc->sc_mtx); + + return 0; +} + + + +/** + * omap3_dma_set_addr_mode - driver attach function + * @ch: the channel number to set the endianess of + * @rd_mode: the xfer source addressing mode (either DMA_ADDR_CONSTANT, + * DMA_ADDR_POST_INCREMENT, DMA_ADDR_SINGLE_INDEX or + * DMA_ADDR_DOUBLE_INDEX) + * @wr_mode: the xfer destination addressing mode (either DMA_ADDR_CONSTANT, + * DMA_ADDR_POST_INCREMENT, DMA_ADDR_SINGLE_INDEX or + * DMA_ADDR_DOUBLE_INDEX) + * + * + * LOCKING: + * DMA registers protected by internal mutex + * + * RETURNS: + * EH_HANDLED or EH_NOT_HANDLED + */ +int +omap3_dma_set_addr_mode(unsigned int ch, unsigned int src_mode, + unsigned int dst_mode) +{ + struct omap3_dma_softc *sc = g_omap3_dma_sc; + uint32_t ccr; + + /* Sanity check */ + if (sc == NULL) + return (ENOMEM); + + mtx_lock(&sc->sc_mtx); + + if ((sc->sc_active_channels & (1 << ch)) == 0) { + mtx_unlock(&sc->sc_mtx); + return (EINVAL); + } + + ccr = sc->sc_channel[ch].reg_ccr; + + ccr &= ~DMA4_CCR_SRC_ADDRESS_MODE(0x3); + ccr |= DMA4_CCR_SRC_ADDRESS_MODE(src_mode); + + ccr &= ~DMA4_CCR_DST_ADDRESS_MODE(0x3); + ccr |= DMA4_CCR_DST_ADDRESS_MODE(dst_mode); + + sc->sc_channel[ch].reg_ccr = ccr; + + sc->sc_channel[ch].need_reg_write = 1; + + mtx_unlock(&sc->sc_mtx); + + return 0; +} + + + + + + Index: sys/arm/cortexa8/omap3/omap3_gpio.h =================================================================== --- sys/arm/cortexa8/omap3/omap3_gpio.h (revision 0) +++ sys/arm/cortexa8/omap3/omap3_gpio.h (revision 0) @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2010 + * Ben Gray . + * All rights reserved. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Ben Gray. + * 4. The name of the company nor the name of the author may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY BEN GRAY ``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 BEN GRAY 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. + */ + + +/** + * Very simple GPIO (general purpose IO) driver module for the TI OMAP3530 SoC. + * + * Currently this driver only does the basics, get a value on a pin & set a + * value on a pin. Hopefully over time I'll expand this to be a bit more generic + * and support interrupts and other various bits on the SoC can do ... in the + * meantime this is all you get. + * + * External Usage + * ~~~~~~~~~~~~~~ + * - Call omap3_gpio_request() to get 'exclusive' access to the GPIO pin, only + * one person can call omap3_gpio_request() on the same pin. However currently + * this module works on the honor system, there is nothing stopping another + * module from changing the state of the pin using the pin number. + * - Use omap3_gpio_direction_output or omap3_gpio_direction_input to change + * the mode of the pin, from an output to an input and vice verse. + * - Use omap3_gpio_pin_get() to get the level of an input pin. + * - Use omap3_gpio_pin_set() to set the level of an output GPIO pin. + * - Call omap3_gpio_free() to release 'exclusive' access to the GPIO pin. + * + */ +#ifndef _OMAP3_GPIO_H_ +#define _OMAP3_GPIO_H_ + +#define GPIO_TRIGGER_LOWLEVEL 0x1 +#define GPIO_TRIGGER_HIGHLEVEL 0x2 +#define GPIO_TRIGGER_RISING 0x4 +#define GPIO_TRIGGER_FALLING 0x8 + + +int +omap3_gpio_request(unsigned int pin, const char *name); + +int +omap3_gpio_free(unsigned int pin); + +int +omap3_gpio_direction_output(unsigned int pin, int val); + +int +omap3_gpio_direction_input(unsigned int pin); + +int +omap3_gpio_pin_get(unsigned int pin); + +int +omap3_gpio_pin_set(unsigned int pin, int val); + +int +omap3_gpio_pin_toggle(unsigned int pin); + + +int +omap3_gpio_pin_intr(unsigned int pin, unsigned int trigger, + void (*callback)(unsigned int pin, unsigned int datain, void *data), + void *data); + +int +omap3_gpio_pin_debounce(unsigned int pin, int enable, unsigned int interval); + + +#endif /* _OMAP3_GPIO_H_ */ Index: sys/arm/cortexa8/omap3/omap3_prcm.h =================================================================== --- sys/arm/cortexa8/omap3/omap3_prcm.h (revision 0) +++ sys/arm/cortexa8/omap3/omap3_prcm.h (revision 0) @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2010 + * Ben Gray . + * All rights reserved. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Ben Gray. + * 4. The name of the company nor the name of the author may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY BEN GRAY ``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 BEN GRAY 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. + */ + + +/* + * Texas Instruments - OMAP3xxx series processors + * + * Reference: + * OMAP35x Applications Processor + * Technical Reference Manual + * (omap35xx_techref.pdf) + */ +#ifndef _OMAP3_PRCM_H_ +#define _OMAP3_PRCM_H_ + + +/* +#define OMAP3_MODULE_DOMAIN_IVA2 1 +#define OMAP3_MODULE_DOMAIN_OCP 2 +#define OMAP3_MODULE_DOMAIN_MPU 3 +#define OMAP3_MODULE_DOMAIN_CORE 4 +#define OMAP3_MODULE_DOMAIN_SGX 5 +#define OMAP3_MODULE_DOMAIN_WKUP 6 +#define OMAP3_MODULE_DOMAIN_CLOCK_CONTROL 7 +#define OMAP3_MODULE_DOMAIN_DSS 8 +#define OMAP3_MODULE_DOMAIN_CAM 9 +#define OMAP3_MODULE_DOMAIN_PER 10 +#define OMAP3_MODULE_DOMAIN_EMU 11 +#define OMAP3_MODULE_DOMAIN_GLOBAL 12 +#define OMAP3_MODULE_DOMAIN_NEON 13 +#define OMAP3_MODULE_DOMAIN_USBHOST 14 +*/ + +#define OMAP3_MODULE_REG_OFFSET(x) (((x) >> 8) & 0xffffff) +#define OMAP3_MODULE_REG_BIT(x) (((x) >> 0) & 0xff) + +#define OMAP3_MODULE_CREATE(r,b) ((((r) & 0xffffff) << 8) | \ + (((b) & 0xff) << 0)) + + + +/* + * MMC/SD/SDIO Module(s) functional and interface clocks + */ +#define OMAP3_MODULE_MMC1_FCLK \ + OMAP3_MODULE_CREATE(OMAP35XX_CM_FCLKEN1_CORE, 24) +#define OMAP3_MODULE_MMC1_ICLK \ + OMAP3_MODULE_CREATE(OMAP35XX_CM_ICLKEN1_CORE, 24) + +#define OMAP3_MODULE_MMC2_FCLK \ + OMAP3_MODULE_CREATE(OMAP35XX_CM_FCLKEN1_CORE, 25) +#define OMAP3_MODULE_MMC2_ICLK \ + OMAP3_MODULE_CREATE(OMAP35XX_CM_ICLKEN1_CORE, 25) + +#define OMAP3_MODULE_MMC3_FCLK \ + OMAP3_MODULE_CREATE(OMAP35XX_CM_FCLKEN1_CORE, 30) +#define OMAP3_MODULE_MMC3_ICLK \ + OMAP3_MODULE_CREATE(OMAP35XX_CM_ICLKEN1_CORE, 30) + +/* + * I2C Module(s) functional and interface clocks + */ +#define OMAP3_MODULE_I2C1_FCLK \ + OMAP3_MODULE_CREATE(OMAP35XX_CM_FCLKEN1_CORE, 15) +#define OMAP3_MODULE_I2C1_ICLK \ + OMAP3_MODULE_CREATE(OMAP35XX_CM_ICLKEN1_CORE, 15) + +#define OMAP3_MODULE_I2C2_FCLK \ + OMAP3_MODULE_CREATE(OMAP35XX_CM_FCLKEN1_CORE, 16) +#define OMAP3_MODULE_I2C2_ICLK \ + OMAP3_MODULE_CREATE(OMAP35XX_CM_ICLKEN1_CORE, 16) + +#define OMAP3_MODULE_I2C3_FCLK \ + OMAP3_MODULE_CREATE(OMAP35XX_CM_FCLKEN1_CORE, 17) +#define OMAP3_MODULE_I2C3_ICLK \ + OMAP3_MODULE_CREATE(OMAP35XX_CM_ICLKEN1_CORE, 17) + +/* + * UART Module(s) functional and interface clocks + */ +#define OMAP3_MODULE_UART1_FCLK \ + OMAP3_MODULE_CREATE(OMAP35XX_CM_FCLKEN1_CORE, 13) +#define OMAP3_MODULE_UART1_ICLK \ + OMAP3_MODULE_CREATE(OMAP35XX_CM_ICLKEN1_CORE, 13) + +#define OMAP3_MODULE_UART2_FCLK \ + OMAP3_MODULE_CREATE(OMAP35XX_CM_FCLKEN1_CORE, 14) +#define OMAP3_MODULE_UART2_ICLK \ + OMAP3_MODULE_CREATE(OMAP35XX_CM_ICLKEN1_CORE, 14) + + +/* + * General Purpose Timers Module(s) functional and interface clocks + */ +#define OMAP3_MODULE_GPTIMER10_FCLK \ + OMAP3_MODULE_CREATE(OMAP35XX_CM_FCLKEN1_CORE, 11) +#define OMAP3_MODULE_GPTIMER10_ICLK \ + OMAP3_MODULE_CREATE(OMAP35XX_CM_ICLKEN1_CORE, 11) + +#define OMAP3_MODULE_GPTIMER11_FCLK \ + OMAP3_MODULE_CREATE(OMAP35XX_CM_FCLKEN1_CORE, 12) +#define OMAP3_MODULE_GPTIMER11_ICLK \ + OMAP3_MODULE_CREATE(OMAP35XX_CM_ICLKEN1_CORE, 12) + + +/* + * USB Module(s) functional and interface clocks + */ +#define OMAP3_MODULE_USBTLL_FCLK \ + OMAP3_MODULE_CREATE(OMAP35XX_CM_FCLKEN3_CORE, 2) +#define OMAP3_MODULE_USBTLL_ICLK \ + OMAP3_MODULE_CREATE(OMAP35XX_CM_ICLKEN3_CORE, 2) +#define OMAP3_MODULE_USBTLL \ + OMAP3_MODULE_CREATE(OMAP35XX_CM_IDLEST3_CORE, 2) + +#define OMAP3_MODULE_USBHOST_120M_FCLK \ + OMAP3_MODULE_CREATE(OMAP35XX_CM_FCLKEN_USBHOST, 1) +#define OMAP3_MODULE_USBHOST_48M_FCLK \ + OMAP3_MODULE_CREATE(OMAP35XX_CM_FCLKEN_USBHOST, 0) +#define OMAP3_MODULE_USBHOST_ICLK \ + OMAP3_MODULE_CREATE(OMAP35XX_CM_ICLKEN_USBHOST, 0) + + + +/* + * GPIO Module(s) functional and interface clocks + */ +#define OMAP3_MODULE_GPIO1_FCLK \ + OMAP3_MODULE_CREATE(OMAP35XX_CM_FCLKEN_WKUP, 3) +#define OMAP3_MODULE_GPIO1_ICLK \ + OMAP3_MODULE_CREATE(OMAP35XX_CM_ICLKEN_WKUP, 3) + +#define OMAP3_MODULE_GPIO2_FCLK \ + OMAP3_MODULE_CREATE(OMAP35XX_CM_FCLKEN_PER, 13) +#define OMAP3_MODULE_GPIO2_ICLK \ + OMAP3_MODULE_CREATE(OMAP35XX_CM_ICLKEN_PER, 13) + +#define OMAP3_MODULE_GPIO3_FCLK \ + OMAP3_MODULE_CREATE(OMAP35XX_CM_FCLKEN_PER, 14) +#define OMAP3_MODULE_GPIO3_ICLK \ + OMAP3_MODULE_CREATE(OMAP35XX_CM_ICLKEN_PER, 14) + +#define OMAP3_MODULE_GPIO4_FCLK \ + OMAP3_MODULE_CREATE(OMAP35XX_CM_FCLKEN_PER, 15) +#define OMAP3_MODULE_GPIO4_ICLK \ + OMAP3_MODULE_CREATE(OMAP35XX_CM_ICLKEN_PER, 15) + +#define OMAP3_MODULE_GPIO5_FCLK \ + OMAP3_MODULE_CREATE(OMAP35XX_CM_FCLKEN_PER, 16) +#define OMAP3_MODULE_GPIO5_ICLK \ + OMAP3_MODULE_CREATE(OMAP35XX_CM_ICLKEN_PER, 16) + +#define OMAP3_MODULE_GPIO6_FCLK \ + OMAP3_MODULE_CREATE(OMAP35XX_CM_FCLKEN_PER, 17) +#define OMAP3_MODULE_GPIO6_ICLK \ + OMAP3_MODULE_CREATE(OMAP35XX_CM_ICLKEN_PER, 17) + + + + + +int +omap3_prcm_enable_clk(unsigned int module); + +int +omap3_prcm_disable_clk(unsigned int module); + +int +omap3_prcm_accessible(unsigned int module); + + + + +#define PRCM_USE_SYSCLK 1 +#define PRCM_USE_32KCLK 0 + +int +omap3_prcm_set_gptimer_clksrc(int timer, int sys_clk); + + +#endif /* _OMAP3_PRCM_H_ */ Index: sys/arm/cortexa8/omap3/omap3_dma.h =================================================================== --- sys/arm/cortexa8/omap3/omap3_dma.h (revision 0) +++ sys/arm/cortexa8/omap3/omap3_dma.h (revision 0) @@ -0,0 +1,226 @@ +/* + * Copyright (c) 2010 + * Ben Gray . + * All rights reserved. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Ben Gray. + * 4. The name of the company nor the name of the author may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY BEN GRAY ``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 BEN GRAY 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. + */ + + +/** + * DMA device driver interface for the TI OMAP3530 SoC + * + * See the omap3_dma.c file for implementation details. + * + * Reference: + * OMAP35x Applications Processor + * Technical Reference Manual + * (omap35xx_techref.pdf) + */ +#ifndef _OMAP3_DMA_H_ +#define _OMAP3_DMA_H_ + + +#define DMA_ENDIAN_BIG 0x1 +#define DMA_ENDIAN_LITTLE 0x0 + +#define DMA_BURST_NONE 0x0 +#define DMA_BURST_16 0x1 +#define DMA_BURST_32 0x2 +#define DMA_BURST_64 0x3 + +#define DMA_DATA_8BITS_SCALAR 0x0 +#define DMA_DATA_16BITS_SCALAR 0x1 +#define DMA_DATA_32BITS_SCALAR 0x2 + +#define DMA_ADDR_CONSTANT 0x0 +#define DMA_ADDR_POST_INCREMENT 0x1 +#define DMA_ADDR_SINGLE_INDEX 0x2 +#define DMA_ADDR_DOUBLE_INDEX 0x3 + + +/** + * Status flags for the DMA callback + * + */ +#define DMA_STATUS_DROP (1UL << 1) +#define DMA_STATUS_HALF (1UL << 2) +#define DMA_STATUS_FRAME (1UL << 3) +#define DMA_STATUS_LAST (1UL << 4) +#define DMA_STATUS_BLOCK (1UL << 5) +#define DMA_STATUS_SYNC (1UL << 6) +#define DMA_STATUS_PKT (1UL << 7) +#define DMA_STATUS_TRANS_ERR (1UL << 8) +#define DMA_STATUS_SECURE_ERR (1UL << 9) +#define DMA_STATUS_SUPERVISOR_ERR (1UL << 10) +#define DMA_STATUS_MISALIGNED_ADRS_ERR (1UL << 11) +#define DMA_STATUS_DRAIN_END (1UL << 12) + +#define DMA_SYNC_FRAME (1UL << 0) +#define DMA_SYNC_BLOCK (1UL << 1) +#define DMA_SYNC_PACKET (DMA_SYNC_FRAME | DMA_SYNC_BLOCK) +#define DMA_SYNC_TRIG_ON_SRC (1UL << 8) +#define DMA_SYNC_TRIG_ON_DST (1UL << 9) + + +#define DMA_IRQ_FLAG_DROP (1UL << 1) +#define DMA_IRQ_FLAG_HALF_FRAME_COMPL (1UL << 2) +#define DMA_IRQ_FLAG_FRAME_COMPL (1UL << 3) +#define DMA_IRQ_FLAG_START_LAST_FRAME (1UL << 4) +#define DMA_IRQ_FLAG_BLOCK_COMPL (1UL << 5) +#define DMA_IRQ_FLAG_ENDOF_PKT (1UL << 7) +#define DMA_IRQ_FLAG_DRAIN (1UL << 12) + + +#define DMA_TRIGGER_SYS_DMA_REQ0 1 /* External DMA request 0 (system expansion) */ +#define DMA_TRIGGER_SYS_DMA_REQ1 2 /* External DMA request 1 (system expansion) */ +#define DMA_TRIGGER_GPMC_DMA 3 /* GPMC request from prefetch engine */ +#define DMA_TRIGGER_DSS_LINE_TRIGGER 5 /* Display subsystem—frame update request */ +#define DMA_TRIGGER_SYS_DMA_REQ2 6 /* External DMA request 2 (system expansion) */ +#define DMA_TRIGGER_AES_1_DMA_TX 8 /* AES crypto-accelerator—transmit request */ +#define DMA_TRIGGER_AES_1_DMA_RX 9 /* AES crypto-accelerator—receive request */ +#define DMA_TRIGGER_DES_1_DMA_TX 10 /* DES/3DES crypto-accelerator—transmit request */ +#define DMA_TRIGGER_DES_1_DMA_RX 11 /* DES/3DES crypto-accelerator—receive request */ +#define DMA_TRIGGER_SHA2MD5_DMA_RX 12 /* SHA2-/MD5 crypto-accelerator—receive request */ +#define DMA_TRIGGER_SPI3_DMA_TX0 14 /* McSPI module 3—transmit request channel 0 */ +#define DMA_TRIGGER_SPI3_DMA_RX0 15 /* McSPI module 3—receive request channel 0 */ +#define DMA_TRIGGER_MCBSP3_DMA_TX 16 /* MCBSP module 3—transmit request */ +#define DMA_TRIGGER_MCBSP3_DMA_RX 17 /* MCBSP module 3—receive request */ +#define DMA_TRIGGER_MCBSP4_DMA_TX 18 /* MCBSP module 4—transmit request */ +#define DMA_TRIGGER_MCBSP4_DMA_RX 19 /* MCBSP module 4—receive request */ +#define DMA_TRIGGER_MCBSP5_DMA_TX 20 /* MCBSP module 5—transmit request */ +#define DMA_TRIGGER_MCBSP5_DMA_RX 21 /* MCBSP module 5—receive request */ +#define DMA_TRIGGER_SPI3_DMA_TX1 22 /* McSPI module 3—transmit request channel 1 */ +#define DMA_TRIGGER_SPI3_DMA_RX1 23 /* McSPI module 3—receive request channel 1 */ +#define DMA_TRIGGER_I2C3_DMA_TX 24 /* I2C module 3—transmit request */ +#define DMA_TRIGGER_I2C3_DMA_RX 25 /* I2C module 3—receive request */ +#define DMA_TRIGGER_I2C1_DMA_TX 26 /* I2C module 1—transmit request */ +#define DMA_TRIGGER_I2C1_DMA_RX 27 /* I2C module 1—receive request */ +#define DMA_TRIGGER_I2C2_DMA_TX 28 /* I2C module 2—transmit request */ +#define DMA_TRIGGER_I2C2_DMA_RX 29 /* I2C module 2—receive request */ +#define DMA_TRIGGER_MCBSP1_DMA_TX 30 /* MCBSP module 1—transmit request */ +#define DMA_TRIGGER_MCBSP1_DMA_RX 31 /* MCBSP module 1—receive request */ +#define DMA_TRIGGER_MCBSP2_DMA_TX 32 /* MCBSP module 2—transmit request */ +#define DMA_TRIGGER_MCBSP2_DMA_RX 33 /* MCBSP module 2—receive request */ +#define DMA_TRIGGER_SPI1_DMA_TX0 34 /* McSPI module 1—transmit request channel 0 */ +#define DMA_TRIGGER_SPI1_DMA_RX0 35 /* McSPI module 1—receive request channel 0 */ +#define DMA_TRIGGER_SPI1_DMA_TX1 36 /* McSPI module 1—transmit request channel 1 */ +#define DMA_TRIGGER_SPI1_DMA_RX1 37 /* McSPI module 1—receive request channel 1 */ +#define DMA_TRIGGER_SPI1_DMA_TX2 38 /* McSPI module 1—transmit request channel 2 */ +#define DMA_TRIGGER_SPI1_DMA_RX2 39 /* McSPI module 1—receive request channel 2 */ +#define DMA_TRIGGER_SPI1_DMA_TX3 40 /* McSPI module 1—transmit request channel 3 */ +#define DMA_TRIGGER_SPI1_DMA_RX3 41 /* McSPI module 1—receive request channel 3 */ +#define DMA_TRIGGER_SPI2_DMA_TX0 42 /* McSPI module 2—transmit request channel 0 */ +#define DMA_TRIGGER_SPI2_DMA_RX0 43 /* McSPI module 2—receive request channel 0 */ +#define DMA_TRIGGER_SPI2_DMA_TX1 44 /* McSPI module 2—transmit request channel 1 */ +#define DMA_TRIGGER_SPI2_DMA_RX1 45 /* McSPI module 2—receive request channel 1 */ +#define DMA_TRIGGER_MMC2_DMA_TX 46 /* MMC/SD2 transmit request */ +#define DMA_TRIGGER_MMC2_DMA_RX 47 /* MMC/SD2 receive request */ +#define DMA_TRIGGER_UART1_DMA_TX 48 /* UART module 1—transmit request */ +#define DMA_TRIGGER_UART1_DMA_RX 49 /* UART module 1—receive request */ +#define DMA_TRIGGER_UART2_DMA_TX 50 /* UART module 2—transmit request */ +#define DMA_TRIGGER_UART2_DMA_RX 51 /* UART module 2—receive request */ +#define DMA_TRIGGER_UART3_DMA_TX 52 /* UART module 3—transmit request */ +#define DMA_TRIGGER_UART3_DMA_RX 53 /* UART module 3—receive request */ +#define DMA_TRIGGER_MMC1_DMA_TX 60 /* MMC/SD1 transmit request */ +#define DMA_TRIGGER_MMC1_DMA_RX 61 /* MMC/SD1 receive request */ +#define DMA_TRIGGER_MS_DMA 62 /* MS-PRO request */ +#define DMA_TRIGGER_SYS_DMA_REQ3 63 /* External DMA request 3 (system expansion) */ +#define DMA_TRIGGER_AES_2_DMA_TX 64 /* AES crypto-accelerator 2—transmit request */ +#define DMA_TRIGGER_AES_2_DMA_RX 65 /* AES crypto-accelerator 2—receive request */ +#define DMA_TRIGGER_DES_2_DMA_TX 66 /* DES/3DES crypto-accelerator 2—transmit request */ +#define DMA_TRIGGER_DES_2_DMA_RX 67 /* DES/3DES crypto-accelerator 2—receive request */ +#define DMA_TRIGGER_SHA1MD5_DMA_RX 68 /* SHA1/MD5 crypto-accelerator 2—receive request */ +#define DMA_TRIGGER_SPI4_DMA_TX0 69 /* McSPI module 4—transmit request channel 0 */ +#define DMA_TRIGGER_SPI4_DMA_RX0 70 /* McSPI module 4—receive request channel 0 */ +#define DMA_TRIGGER_DSS_DMA0 71 /* Display subsystem DMA request 0 (DSI) */ +#define DMA_TRIGGER_DSS_DMA1 72 /* Display subsystem DMA request 1 (DSI) */ +#define DMA_TRIGGER_DSS_DMA2 73 /* Display subsystem DMA request 2 (DSI) */ +#define DMA_TRIGGER_DSS_DMA3 74 /* Display subsystem DMA request 3 (DSI or RFBI) */ +#define DMA_TRIGGER_MMC3_DMA_TX 76 /* MMC/SD3 transmit request */ +#define DMA_TRIGGER_MMC3_DMA_RX 77 /* MMC/SD3 receive request */ +#define DMA_TRIGGER_USIM_DMA_TX 78 /* USIM transmit request */ +#define DMA_TRIGGER_USIM_DMA_RX 79 /* USIM receive request */ + + + + + +int +omap3_dma_activate_channel(unsigned int *ch, + void (*callback)(unsigned int ch, uint32_t status, void *data), + void *data); + +int +omap3_dma_deactivate_channel(unsigned int ch); + +int +omap3_dma_start_xfer(unsigned int ch, unsigned int src_paddr, + unsigned long dst_paddr, + unsigned int frmcnt, unsigned int elmcnt); + +int +omap3_dma_start_xfer_packet(unsigned int ch, unsigned int src_paddr, + unsigned long dst_paddr, unsigned int frmcnt, + unsigned int elmcnt, unsigned int pktsize); + +int +omap3_dma_stop_xfer(unsigned int ch); + +int +omap3_dma_enable_channel_irq(unsigned int ch, uint32_t flags); + +int +omap3_dma_disable_channel_irq(unsigned int ch); + +int +omap3_dma_get_channel_status(unsigned int ch, uint32_t *status); + + +int +omap3_dma_set_xfer_endianess(unsigned int ch, unsigned int src, unsigned int dst); + +int +omap3_dma_set_xfer_burst(unsigned int ch, unsigned int src, unsigned int dst); + +int +omap3_dma_set_xfer_data_type(unsigned int ch, unsigned int type); + +int +omap3_dma_set_callback(unsigned int ch, + void (*callback)(unsigned int ch, uint32_t status, void *data), + void *data); + +int +omap3_dma_sync_params(unsigned int ch, unsigned int trigger, unsigned int mode); + +int +omap3_dma_set_addr_mode(unsigned int ch, unsigned int src_mode, + unsigned int dst_mode); + + +#endif /* _OMAP3_DMA_H_ */ Index: sys/arm/cortexa8/omap3/omap3_space_asm.S =================================================================== --- sys/arm/cortexa8/omap3/omap3_space_asm.S (revision 0) +++ sys/arm/cortexa8/omap3/omap3_space_asm.S (revision 0) @@ -0,0 +1,183 @@ +/* $NetBSD: bus_space_asm_generic.S,v 1.3 2003/03/27 19:46:14 mycroft Exp $ */ + +/*- + * Copyright (c) 1997 Causality Limited. + * Copyright (c) 1997 Mark Brinicombe. + * All rights reserved. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Mark Brinicombe + * for the NetBSD Project. + * 4. The name of the company nor the name of the author may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 +__FBSDID("$FreeBSD$"); + +/* + * Generic bus_space functions. + */ + +/* + * read single + */ + +ENTRY(generic_armv7_bs_r_2) + ldrh r0, [r1, r2] + RET + +/* + * write single + */ + +ENTRY(generic_armv7_bs_w_2) + strh r3, [r1, r2] + RET + +/* + * read multiple + */ + +ENTRY(generic_armv7_bs_rm_2) + add r0, r1, r2 + mov r1, r3 + ldr r2, [sp, #0] + teq r2, #0 + RETeq + +1: ldrh r3, [r0] + strh r3, [r1], #2 + subs r2, r2, #1 + bne 1b + + RET + +/* + * write multiple + */ + +ENTRY(generic_armv7_bs_wm_2) + add r0, r1, r2 + mov r1, r3 + ldr r2, [sp, #0] + teq r2, #0 + RETeq + +1: ldrh r3, [r1], #2 + strh r3, [r0] + subs r2, r2, #1 + bne 1b + + RET + +/* + * read region + */ + +ENTRY(generic_armv7_bs_rr_2) + add r0, r1, r2 + mov r1, r3 + ldr r2, [sp, #0] + teq r2, #0 + RETeq + +1: ldrh r3, [r0], #2 + strh r3, [r1], #2 + subs r2, r2, #1 + bne 1b + + RET + +/* + * write region. + */ + +ENTRY(generic_armv7_bs_wr_2) + add r0, r1, r2 + mov r1, r3 + ldr r2, [sp, #0] + teq r2, #0 + RETeq + +1: ldrh r3, [r1], #2 + strh r3, [r0], #2 + subs r2, r2, #1 + bne 1b + + RET + +/* + * set region + */ + +ENTRY(generic_armv7_bs_sr_2) + add r0, r1, r2 + mov r1, r3 + ldr r2, [sp, #0] + teq r2, #0 + RETeq + +1: strh r1, [r0], #2 + subs r2, r2, #1 + bne 1b + + RET + +/* + * copy region + */ + +ENTRY(generic_armv7_bs_c_2) + add r0, r1, r2 + ldr r2, [sp, #0] + add r1, r2, r3 + ldr r2, [sp, #4] + teq r2, #0 + RETeq + + cmp r0, r1 + blt 2f + +1: ldrh r3, [r0], #2 + strh r3, [r1], #2 + subs r2, r2, #1 + bne 1b + + RET + +2: add r0, r0, r2, lsl #1 + add r1, r1, r2, lsl #1 + sub r0, r0, #2 + sub r1, r1, #2 + +3: ldrh r3, [r0], #-2 + strh r3, [r1], #-2 + subs r2, r2, #1 + bne 3b + + RET Index: sys/arm/cortexa8/omap3/omap3_intr.c =================================================================== --- sys/arm/cortexa8/omap3/omap3_intr.c (revision 0) +++ sys/arm/cortexa8/omap3/omap3_intr.c (revision 0) @@ -0,0 +1,258 @@ +/* + * Copyright (c) 2010 + * Ben Gray . + * All rights reserved. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Ben Gray. + * 4. The name of the company nor the name of the author may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY BEN GRAY ``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 BEN GRAY 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include + +#include +#include + + + +/* + * There are a number of ways that interrupt handling is implemented in + * the various ARM platforms, the PXA has the neatest way, it creates another + * device driver that handles everything. However IMO this is rather heavy- + * weight for playing with IRQs which should be quite fast ... so I've + * gone for something similar to the IXP425, which just directly plays with + * registers. This assumes that the interrupt control registers are already + * mapped in virtual memory at a fixed virtual address ... simplies. + * + * The intcps (OMAP3 interrupt controller) has some nice registers, were + * you write a bit to clear or set the mask register ... I think in theory + * that means that you don't need to disable interrupts while doing this, + * because it is an atomic operation. + * + * TODO: check this. + * + */ + + + +/** + * omap3_mask_all_intr - masks all interrupts + * + * Called during initialisation to ensure all interrupts are masked before + * globally enabling interrupts. Should only be used at startup time. + * + * RETURNS: + * nothing + */ +void +omap3_mask_all_intr(void) +{ + unsigned int i; + + for (i = 0; i < 3; i++) { + *((volatile u_int32_t*)OMAP35XX_INTCPS_MIR_SET(i)) = 0xFFFFFFFF; + } +} + + +/** + * omap3_post_filter_intr - called after the IRQ has been filtered + * @arg: the IRQ number + * + * Called after the interrupt handler has done it's stuff, can be used to + * clean up interrupts that haven't been handled properly. + * + * + * RETURNS: + * nothing + */ +void +omap3_post_filter_intr(void *arg) +{ + /* uintptr_t irq = (uintptr_t) arg; */ + + /* data synchronization barrier */ + cpu_drain_writebuf(); +} + + +/** + * omap3_setup_intr - initialises and unmasks the IRQ. + * @dev: + * @child: + * @res: + * @flags: + * @filt: + * @intr: + * @arg: + * @cookiep: + * + * + * + * + * RETURNS: + * 0 on success + */ +int +omap3_setup_intr(device_t dev, device_t child, + struct resource *res, int flags, driver_filter_t *filt, + driver_intr_t *intr, void *arg, void **cookiep) +{ + unsigned int i; + + /* Macro .. does something ? */ + BUS_SETUP_INTR(device_get_parent(dev), child, res, flags, filt, intr, + arg, cookiep); + + /* Enable all the interrupts in the range ... will probably be only one */ + for (i = rman_get_start(res); (i < 96) && (i <= rman_get_end(res)); i++) + { + arm_unmask_irq(i); + } + + return (0); +} + +/** + * omap3_teardown_intr - + * @dev: + * @child: + * @res: + * @cookie: + * + * + * + * + * RETURNS: + * 0 on success + */ +int +omap3_teardown_intr(device_t dev, device_t child, struct resource *res, + void *cookie) +{ + unsigned int i; + + /* Mask (disable) all the interrupts in the range ... will probably be only one */ + for (i = rman_get_start(res); (i < 96) && (i <= rman_get_end(res)); i++) + { + arm_mask_irq(i); + } + + return (BUS_TEARDOWN_INTR(device_get_parent(dev), child, res, cookie)); +} + + + +/** + * arm_mask_irq - masks an IRQ (disables it) + * @nb: the number of the IRQ to mask (disable) + * + * Disables the interrupt at the HW level. + * + * + * RETURNS: + * nothing + */ +void +arm_mask_irq(uintptr_t nb) +{ + *((volatile u_int32_t*)OMAP35XX_INTCPS_MIR_SET(nb >> 5)) + = 1 << (nb & 0x1F); +} + + +/** + * arm_unmask_irq - unmasks an IRQ (enables it) + * @nb: the number of the IRQ to unmask (enable) + * + * Enables the interrupt at the HW level. + * + * + * RETURNS: + * nothing + */ +void +arm_unmask_irq(uintptr_t nb) +{ + *((volatile u_int32_t*)OMAP35XX_INTCPS_MIR_CLEAR(nb >> 5)) + = 1 << (nb & 0x1F); +} + + + +/** + * arm_get_next_irq - gets the next tripped interrupt + * @last_irq: the number of the last IRQ processed + * + * Enables the interrupt at the HW level. + * + * + * RETURNS: + * nothing + */ +int +arm_get_next_irq(int last_irq) +{ + volatile u_int32_t* preg; + uint32_t active_irq; + + /* clean-up the last IRQ */ + if (last_irq != -1) { + + /* clear the interrupt status flag */ + preg = (volatile u_int32_t*) OMAP35XX_INTCPS_ISR_CLEAR(last_irq >> 5); + *preg = (0x1UL << (last_irq & 0x1F)); + + /* tell the interrupt logic we've dealt with the interrupt */ + preg = (volatile u_int32_t*) OMAP35XX_INTCPS_CONTROL; + *preg = 0x1UL; + } + + /* Get the next active interrupt */ + preg = (volatile u_int32_t*) OMAP35XX_INTCPS_SIR_IRQ; + active_irq = *preg; + + /* Check for spurious interrupt */ + if ((active_irq & 0xffffff80) == 0xffffff80) { + printf("[BRG] Spurious interrupt detected [0x%08x]\n", active_irq); + return -1; + } + + /* Just get the active IRQ part */ + active_irq &= 0x7F; + + /* Return the new IRQ if it is different from the previous */ + if (active_irq != last_irq) + return active_irq; + else + return -1; +} Index: sys/arm/cortexa8/omap3/omap3_mmc.c =================================================================== --- sys/arm/cortexa8/omap3/omap3_mmc.c (revision 0) +++ sys/arm/cortexa8/omap3/omap3_mmc.c (revision 0) @@ -0,0 +1,1515 @@ +/* + * Copyright (c) 2010 + * Ben Gray . + * All rights reserved. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Ben Gray. + * 4. The name of the company nor the name of the author may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY BEN GRAY ``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 BEN GRAY 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. + */ + +/** + * Driver for the MMC/SD/SDIO module on the TI OMAP3530 SoC. + * + * This driver is heavily based on the SD/MMC driver for the AT91 (at91_mci.c). + * + * It's important to realise that the MMC state machine is already in the kernel + * and this driver only exposes the specific interfaces of the controller. + * + * This driver is still very much a work in progress, I've verified that basic + * sector reading can be performed. But I've yet to test it with a file system + * or even writing. In addition I've only tested the driver with an SD card, + * I've no idea if MMC cards work. + * + */ +#include +__FBSDID("$FreeBSD$"); + +#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 "mmcbr_if.h" +#include "mmcbus_if.h" + + +#include +#include + +#include +#include +#include +#include +#include + + + + + +/** + * Structure that stores the driver context + */ +struct omap3_mmc_softc { + device_t sc_dev; + bus_space_tag_t sc_iotag; + bus_space_handle_t sc_ioh; + + bus_dma_tag_t sc_dmatag; + bus_dmamap_t sc_dmamap; + int sc_dmamapped; + + unsigned int sc_dmach_rd; + unsigned int sc_dmach_wr; + + void* sc_irq_h; + struct resource* sc_irq_res; /* IRQ resource */ + + int sc_wp_gpio_pin; /* GPIO pin for MMC write protect */ + + struct mtx sc_mtx; + + struct mmc_host host; + struct mmc_request* req; + struct mmc_command* curcmd; + + int flags; +#define CMD_STARTED 1 +#define STOP_STARTED 2 + + int bus_busy; /* TODO: Needed ? */ + + void * sc_cmd_data_vaddr; + int sc_cmd_data_len; + +}; + +/** + * Macros for driver mutex locking + */ +#define OMAP3_MMC_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) +#define OMAP3_MMC_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) +#define OMAP3_MMC_LOCK_INIT(_sc) \ + mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), \ + "mmc", MTX_DEF) +#define OMAP3_MMC_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx); +#define OMAP3_MMC_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED); +#define OMAP3_MMC_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED); + + + + + +/** + * omap3_mmc_readl - reads a 32-bit value from a register + * @sc: pointer to the driver context + * @off: register offset to read from + * + * LOCKING: + * None + * + * RETURNS: + * The 32-bit value read from the register + */ +static inline uint32_t +omap3_mmc_readl(struct omap3_mmc_softc *sc, bus_size_t off) +{ + return bus_space_read_4(sc->sc_iotag, sc->sc_ioh, off); +} + +/** + * omap3_mmc_writel - writes a 32-bit value to a register + * @sc: pointer to the driver context + * @off: register offset to write to + * @val: the value to write into the register + * + * LOCKING: + * None + * + * RETURNS: + * nothing + */ +static inline void +omap3_mmc_writel(struct omap3_mmc_softc *sc, bus_size_t off, uint32_t val) +{ + bus_space_write_4(sc->sc_iotag, sc->sc_ioh, off, val); +} + + + +/* bus entry points */ +static int omap3_mmc_probe(device_t dev); +static int omap3_mmc_attach(device_t dev); +static int omap3_mmc_detach(device_t dev); +static void omap3_mmc_intr(void *arg); +static void omap3_mmc_dma_intr(unsigned int ch, uint32_t status, void *data); +static void omap3_mmc_start(struct omap3_mmc_softc *sc); + +/* helper routines */ +static int omap3_mmc_activate(device_t dev); +static void omap3_mmc_deactivate(device_t dev); + + + + + + + +/** + * omap3_mmc_init - initialises the MMC/SD/SIO controller + * @dev: mmc device handle + * + * Called by the driver attach function during driver initialisation. This + * function is responsibly to setup the controller ready for transactions. + * + * LOCKING: + * No locking, assumed to only be called during initialisation. + * + * RETURNS: + * nothing + */ +static void +omap3_mmc_init(device_t dev) +{ + struct omap3_mmc_softc *sc = device_get_softc(dev); + uint32_t val; + uint32_t i; + + /* 1: Enable the controller and interface/functional clocks */ + + /* Set the EN_MMC1 bit (MMC SDIO 1 interface clock control) */ + omap3_prcm_enable_clk(OMAP3_MODULE_MMC1_FCLK); + + /* Set the EN_MMC1 bit (MMC1 functional clock control) */ + omap3_prcm_enable_clk(OMAP3_MODULE_MMC1_ICLK); + + + + + /* 2: Issue a softreset to the controller */ + omap3_mmc_writel(sc, OMAP35XX_MMCHS_SYSCONFIG, 0x0002); + while ((omap3_mmc_readl(sc, OMAP35XX_MMCHS_SYSSTATUS) & 0x01) == 0x00) + continue; + + + /* 3: MMCHS Controller Voltage Capabilities Initialization */ + val = omap3_mmc_readl(sc, OMAP35XX_MMCHS_CAPA); + omap3_mmc_writel(sc, OMAP35XX_MMCHS_CAPA, (val | MMCHS_CAPA_VS30 | + MMCHS_CAPA_VS18)); + + + + + /* 4: MMCHS Controller Default Initialization */ + + /* 4a: data bus width = 1, voltage = 1.8v, MMC bus power is on (not card's power) */ + omap3_mmc_writel(sc, OMAP35XX_MMCHS_HCTL, 0x00000b00); + + /* 4b: card's clock enable and card's clock frequency divider. */ + omap3_mmc_writel(sc, OMAP35XX_MMCHS_SYSCTL, 0x0000a007); + + /* 4c: Set MMC bus mode to open drain. */ + omap3_mmc_writel(sc, OMAP35XX_MMCHS_CON, 0x00000001); + + + + /* 5: MMCHS Controller INIT Procedure Start */ + + /* Prior to issuing any command, the MMCHS controller has to execute a special + * INIT procedure. The MMCHS controller has to generate a clock during 1ms. + * During the INIT procedure, the MMCHS controller generates 80 clock periods. + * In order to keep the 1ms gap, the MMCHS controller should be configured + * to generate a clock whose frequency is smaller or equal to 80 KHz. If the + * MMCHS controller divider bitfield width doesn't allow to choose big values, + * the MMCHS controller driver should perform the INIT procedure twice or + * three times. Twice is generally enough. + * + * The INIt procedure is executed by setting MMCHS1.MMCHS_CON[1] INIT + * bitfield to 1 and by sending a dummy command, writing 0x00000000 in + * MMCHS1.MMCHS_CMD register. + */ + for (i=0; i<3; i++) { + + /* sets MMCHS1.MMCHS_CON[1] INIT to 1 */ + val = omap3_mmc_readl(sc, OMAP35XX_MMCHS_CON); + val |= 0x00000002; + omap3_mmc_writel(sc, OMAP35XX_MMCHS_CON, val); + + /* sends dummy command */ + omap3_mmc_writel(sc, OMAP35XX_MMCHS_CMD, 0x00000000); + } + + + /* 6: MMCHS Controller Pre-card Identification Configuration */ + + /* Before card identification starts, the MMCHS controller's configuration + * should change. MMC card's clock should now be 400 KHz according to MMC + * system spec requirements. + */ + + /* data bus width = 1, voltage = 1.8v, MMC bus power is on (not card's power) */ + omap3_mmc_writel(sc, OMAP35XX_MMCHS_HCTL, 0x00000b00); + + /* card's clock enable and card's clock frequency divider. */ + omap3_mmc_writel(sc, OMAP35XX_MMCHS_SYSCTL, 0x00003C07); + + /* Set MMC bus mode to open drain. */ + omap3_mmc_writel(sc, OMAP35XX_MMCHS_CON, 0x00000001); + + +} + + +/** + * omap3_mmc_fini - shutdown the MMC/SD/SIO controller + * @dev: mmc device handle + * + * Responsible for shutting done the MMC controller, this function may be + * called as part of a reset sequence. + * + * LOCKING: + * No locking, assumed to be called during tear-down/reset. + * + * RETURNS: + * nothing + */ +static void +omap3_mmc_fini(device_t dev) +{ + /* TODO: Cleanup properly */ + + /* Disable the interrupts */ + + /* Disable the functional and interface clocks */ + omap3_prcm_disable_clk(OMAP3_MODULE_MMC1_FCLK); + omap3_prcm_disable_clk(OMAP3_MODULE_MMC1_ICLK); + +} + + + +/** + * omap3_mmc_probe - probe function for the driver + * @dev: mmc device handle + * + * + * + * RETURNS: + * always returns 0 + */ +static int +omap3_mmc_probe(device_t dev) +{ + + device_set_desc(dev, "TI OMAP3530 MMC/SD/SIO host bridge"); + return (0); +} + +/** + * omap3_mmc_attach - attach function for the driver + * @dev: mmc device handle + * + * Driver initialisation, sets-up the bus mappings, DMA mapping/channels and + * the actual controller by calling omap3_mmc_init(). + * + * RETURNS: + * Returns 0 on success or a negative error code. + */ +static int +omap3_mmc_attach(device_t dev) +{ + struct omap3_mmc_softc *sc = device_get_softc(dev); + int err; + device_t child; + + /* Save the device and bus tag */ + sc->sc_dev = dev; + sc->sc_iotag = &omap3_bs_tag; + + /* Initiate the mtex lock */ + OMAP3_MMC_LOCK_INIT(sc); + + /* Indicate the DMA channels haven't yet been allocated */ + sc->sc_dmach_rd = (unsigned int)-1; + sc->sc_dmach_wr = (unsigned int)-1; + + + /* Get the hint'ed write detect pin */ + if (resource_int_value("omap3_mmc", 0, "wp_gpio", &sc->sc_wp_gpio_pin) != 0){ + sc->sc_wp_gpio_pin = -1; + } else { + /* Change the PADCONF so the pin is an input mode (assume HW pull-ups) */ + omap3_scm_padconf_set_gpiomode(sc->sc_wp_gpio_pin, PADCONF_PIN_INPUT); + + /* Request the GPIO pin and make it an input */ + if (omap3_gpio_request(sc->sc_wp_gpio_pin, "MMC_WP") != 0) + sc->sc_wp_gpio_pin = -1; + else + omap3_gpio_direction_input(sc->sc_wp_gpio_pin); + } + + + /* Activate the device */ + err = omap3_mmc_activate(dev); + if (err) + goto out; + + + /* Allocate DMA tags and maps */ + err = bus_dma_tag_create(bus_get_dma_tag(dev), 1, 0, + BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, + NULL, MAXPHYS, 1, MAXPHYS, BUS_DMA_ALLOCNOW, NULL, + NULL, &sc->sc_dmatag); + if (err != 0) + goto out; + + err = bus_dmamap_create(sc->sc_dmatag, 0, &sc->sc_dmamap); + if (err != 0) + goto out; + + + /* Activate a RX channel from the OMAP3 DMA driver */ + err = omap3_dma_activate_channel(&sc->sc_dmach_rd, omap3_mmc_dma_intr, sc); + if (err != 0) + goto out; + err = omap3_dma_enable_channel_irq(sc->sc_dmach_rd, DMA_IRQ_FLAG_FRAME_COMPL); + if (err != 0) + goto out; + err = omap3_dma_set_xfer_burst(sc->sc_dmach_rd, DMA_BURST_NONE, DMA_BURST_64); + if (err != 0) + goto out; + err = omap3_dma_set_xfer_data_type(sc->sc_dmach_rd, DMA_DATA_32BITS_SCALAR); + if (err != 0) + goto out; + err = omap3_dma_sync_params(sc->sc_dmach_rd, DMA_TRIGGER_MMC1_DMA_RX, + DMA_SYNC_PACKET | DMA_SYNC_TRIG_ON_SRC); + if (err != 0) + goto out; + err = omap3_dma_set_addr_mode(sc->sc_dmach_rd, DMA_ADDR_CONSTANT, + DMA_ADDR_POST_INCREMENT); + if (err != 0) + goto out; + + + /* Activate and configure the TX DMA channel */ + err = omap3_dma_activate_channel(&sc->sc_dmach_wr, omap3_mmc_dma_intr, sc); + if (err != 0) + goto out; + err = omap3_dma_enable_channel_irq(sc->sc_dmach_wr, DMA_IRQ_FLAG_FRAME_COMPL); + if (err != 0) + goto out; + err = omap3_dma_set_xfer_burst(sc->sc_dmach_wr, DMA_BURST_64, DMA_BURST_NONE); + if (err != 0) + goto out; + err = omap3_dma_set_xfer_data_type(sc->sc_dmach_wr, DMA_DATA_32BITS_SCALAR); + if (err != 0) + goto out; + err = omap3_dma_sync_params(sc->sc_dmach_wr, DMA_TRIGGER_MMC1_DMA_TX, + DMA_SYNC_PACKET | DMA_SYNC_TRIG_ON_DST); + if (err != 0) + goto out; + err = omap3_dma_set_addr_mode(sc->sc_dmach_wr, DMA_ADDR_POST_INCREMENT, + DMA_ADDR_CONSTANT); + if (err != 0) + goto out; + + + + /* Shutdown and restart the controller */ + omap3_mmc_fini(dev); + omap3_mmc_init(dev); + + + /* Activate the interrupt and attach a handler */ + err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_MISC | INTR_MPSAFE, + NULL, omap3_mmc_intr, sc, &sc->sc_irq_h); + if (err != 0) + goto out; + + + /* Add host details */ + sc->host.f_min = OMAP3_MMC_REF_CLK / 1023; + sc->host.f_max = OMAP3_MMC_REF_CLK; + sc->host.host_ocr = MMC_OCR_320_330 | MMC_OCR_330_340; + sc->host.caps = MMC_CAP_4_BIT_DATA; + + child = device_add_child(dev, "mmc", 0); + + device_set_ivars(dev, &sc->host); + err = bus_generic_attach(dev); + +out: + if (err) { + OMAP3_MMC_LOCK_DESTROY(sc); + omap3_mmc_deactivate(dev); + + if (sc->sc_dmach_rd != (unsigned int)-1) + omap3_dma_deactivate_channel(sc->sc_dmach_rd); + if (sc->sc_dmach_wr != (unsigned int)-1) + omap3_dma_deactivate_channel(sc->sc_dmach_wr); + } + + return (err); +} + + + +/** + * omap3_mmc_detach - dettach function for the driver + * @dev: mmc device handle + * + * Shutdowns the controll and release resources allocated by the driver. + * + * RETURNS: + * Always returns 0. + */ +static int +omap3_mmc_detach(device_t dev) +{ + struct omap3_mmc_softc *sc = device_get_softc(dev); + + omap3_mmc_fini(dev); + omap3_mmc_deactivate(dev); + + omap3_dma_deactivate_channel(sc->sc_dmach_wr); + omap3_dma_deactivate_channel(sc->sc_dmach_rd); + + if (sc->sc_wp_gpio_pin != -1) { + omap3_gpio_free(sc->sc_wp_gpio_pin); + sc->sc_wp_gpio_pin = -1; + } + + return (0); +} + + + +/** + * omap3_mmc_activate - activates the driver + * @dev: mmc device handle + * + * Maps in the register set and requests an IRQ handler for the MMC controller. + * + * LOCKING: + * None required + * + * RETURNS: + * 0 on sucess + * ENOMEM if failed to map register set + */ +static int +omap3_mmc_activate(device_t dev) +{ + struct omap3_mmc_softc *sc = device_get_softc(dev); + int rid = 0; + + /* Map the register set for the MMC controller */ + if (bus_space_map(sc->sc_iotag, OMAP35XX_MMCHS1_HWBASE, OMAP35XX_MMCHS_SIZE, + 0, &sc->sc_ioh)) { + panic("%s: Cannot map registers", device_get_name(dev)); + sc->sc_ioh = 0; + } + + /* Allocate an IRQ resource for the MMC controller */ + sc->sc_irq_res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, OMAP35XX_IRQ_MMC1, + OMAP35XX_IRQ_MMC1, 1, RF_ACTIVE); + if (sc->sc_irq_res == NULL) + goto errout; + + return (0); + +errout: + omap3_mmc_deactivate(dev); + return (ENOMEM); +} + + + +/** + * omap3_mmc_deactivate - deactivates the driver + * @dev: mmc device handle + * + * Unmaps the register set and releases the IRQ resource. + * + * LOCKING: + * None required + * + * RETURNS: + * nothing + */ +static void +omap3_mmc_deactivate(device_t dev) +{ + struct omap3_mmc_softc *sc= device_get_softc(dev); + + /* Remove the IRQ handler */ + if (sc->sc_irq_h != NULL) { + bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_irq_h); + sc->sc_irq_h = NULL; + } + + /* Do the generic detach */ + bus_generic_detach(sc->sc_dev); + + /* Unmap the MMC controller registers */ + if (sc->sc_ioh != 0) { + bus_space_unmap(sc->sc_iotag, sc->sc_ioh, OMAP35XX_MMCHS_SIZE); + sc->sc_ioh = 0; + } + + /* Release the IRQ resource */ + if (sc->sc_irq_res != NULL) { + bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(sc->sc_irq_res), + sc->sc_irq_res); + sc->sc_irq_res = NULL; + } + + return; +} + + +/** + * omap3_mmc_getaddr - called by the DMA function to simply return the phys address + * @arg: caller supplied arg + * @segs: array of segments (although in our case should only be one) + * @nsegs: number of segments (in our case should be 1) + * @error: + * + * This function is called by bus_dmamap_load() after it has compiled an array + * of segments, each segment is a phsyical chunk of memory. However in our case + * we should only have one segment, because we don't (yet?) support DMA scatter + * gather. To ensure we only have one segment, the DMA tag was created by + * bus_dma_tag_create() (called from omap_mmc_attach) with nsegments set to 1. + * + */ +static void +omap3_mmc_getaddr(void *arg, bus_dma_segment_t *segs, int nsegs, int error) +{ + if (error != 0) + return; + + *(bus_addr_t *)arg = segs[0].ds_addr; +} + + + + +/** + * omap3_mmc_dma_intr - interrupt handler for DMA events triggered by the controller + * @ch: the dma channel number + * @status: bit field of the status bytes + * @data: callback data, in this case a pointer to the controller struct + * + * + * LOCKING: + * Called from interrupt context + * + */ +static void +omap3_mmc_dma_intr(unsigned int ch, uint32_t status, void *data) +{ + /* Ignore for now ... we don't need this interrupt as we already have the + * interrupt from the MMC controller. + */ +} + + + +/** + * omap3_mmc_intr_xfer_compl - called if a 'transfer complete; IRQ was received + * @sc: pointer to the driver context + * @cmd: the command that was sent previously + * + * This function is simply responsible for syncing up the DMA buffer. + * + * LOCKING: + * Called from interrupt context + * + * RETURNS: + * Return value indicates if the transaction is complete, not done = 0, done != 0 + */ +static int +omap3_mmc_intr_xfer_compl(struct omap3_mmc_softc *sc, struct mmc_command *cmd) +{ + uint32_t cmd_reg; + + + /* Read command register to test whether this command was a read or write. */ + cmd_reg = omap3_mmc_readl(sc, OMAP35XX_MMCHS_CMD); + + /* Sync-up the DMA buffer so the caller can access the new memory */ + if (cmd_reg & MMCHS_CMD_DDIR) { + bus_dmamap_sync(sc->sc_dmatag, sc->sc_dmamap, BUS_DMASYNC_POSTREAD); + bus_dmamap_unload(sc->sc_dmatag, sc->sc_dmamap); + } + else { + bus_dmamap_sync(sc->sc_dmatag, sc->sc_dmamap, BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(sc->sc_dmatag, sc->sc_dmamap); + } + sc->sc_dmamapped--; + + + /* Debugging dump of the data received */ +#if 0 + { + int i; + uint8_t *p = (uint8_t*) sc->sc_cmd_data_vaddr; + for (i=0; isc_cmd_data_len; i++) { + if ((i % 16) == 0) + printf("\n0x%04x : ", i); + printf("%02X ", *p++); + } + printf("\n"); + } +#endif + + /* We are done, transfer complete */ + return 1; +} + + +/** + * omap3_mmc_intr_cmd_compl - called if a 'command complete' IRQ was received + * @sc: pointer to the driver context + * @cmd: the command that was sent previously + * + * + * LOCKING: + * Called from interrupt context + * + * RETURNS: + * Return value indicates if the transaction is complete, not done = 0, done != 0 + */ +static int +omap3_mmc_intr_cmd_compl(struct omap3_mmc_softc *sc, struct mmc_command *cmd) +{ + uint32_t cmd_reg; + + + /* Copy the response into the request struct ... if a response was + * expected */ + if (cmd != NULL && (cmd->flags & MMC_RSP_PRESENT)) { + if (cmd->flags & MMC_RSP_136) { + cmd->resp[3] = omap3_mmc_readl(sc, OMAP35XX_MMCHS_RSP10); + cmd->resp[2] = omap3_mmc_readl(sc, OMAP35XX_MMCHS_RSP32); + cmd->resp[1] = omap3_mmc_readl(sc, OMAP35XX_MMCHS_RSP54); + cmd->resp[0] = omap3_mmc_readl(sc, OMAP35XX_MMCHS_RSP76); + } else { + cmd->resp[0] = omap3_mmc_readl(sc, OMAP35XX_MMCHS_RSP10); + } + } + + /* Check if the command was expecting some data transfer, if not + * we are done. */ + cmd_reg = omap3_mmc_readl(sc, OMAP35XX_MMCHS_CMD); + return ((cmd_reg & MMCHS_CMD_DP) == 0); +} + + +/** + * omap3_mmc_intr_error - handles error interrupts + * @sc: pointer to the driver context + * @cmd: the command that was sent previously + * @stat_reg: the value that was in the status register + * + * + * LOCKING: + * Called from interrupt context + * + * RETURNS: + * Return value indicates if the transaction is complete, not done = 0, done != 0 + */ +static int +omap3_mmc_intr_error(struct omap3_mmc_softc *sc, struct mmc_command *cmd, + uint32_t stat_reg) +{ + uint32_t sysctl_reg; + + /* Ignore CRC errors on CMD2 and ACMD47, per relevant standards */ + if ((stat_reg & MMCHS_STAT_CCRC) && (cmd->opcode == MMC_SEND_OP_COND || + cmd->opcode == ACMD_SD_SEND_OP_COND)) + cmd->error = MMC_ERR_NONE; + else if (stat_reg & (MMCHS_STAT_CTO | MMCHS_STAT_DTO)) + cmd->error = MMC_ERR_TIMEOUT; + else if (stat_reg & (MMCHS_STAT_CCRC | MMCHS_STAT_DCRC)) + cmd->error = MMC_ERR_BADCRC; + else + cmd->error = MMC_ERR_FAILED; + + + /* Abort the DMA transfer (DDIR bit tells direction) */ + if (omap3_mmc_readl(sc, OMAP35XX_MMCHS_CMD) & MMCHS_CMD_DDIR) + omap3_dma_stop_xfer(sc->sc_dmach_rd); + else + omap3_dma_stop_xfer(sc->sc_dmach_wr); + + + /* If an error occure abort the DMA operation and free the dma map */ + if ((sc->sc_dmamapped > 0) && (cmd->error != MMC_ERR_NONE)) { + bus_dmamap_unload(sc->sc_dmatag, sc->sc_dmamap); + sc->sc_dmamapped--; + } + + + /* Data error occured? ... if so issue a soft reset for the data line */ + if (stat_reg & (MMCHS_STAT_DEB | MMCHS_STAT_DCRC | MMCHS_STAT_DTO)) { + + /* Reset the data lines and wait for it to complete */ + sysctl_reg = omap3_mmc_readl(sc, OMAP35XX_MMCHS_SYSCTL); + sysctl_reg |= MMCHS_SYSCTL_SRD; + omap3_mmc_writel(sc, OMAP35XX_MMCHS_SYSCTL, sysctl_reg); + + /* TODO: This is probably not a good idea in an IRQ routine */ + while (omap3_mmc_readl(sc, OMAP35XX_MMCHS_SYSCTL) & MMCHS_SYSCTL_SRD) + continue; + } + + /* On any error the command is cancelled ... so we are done */ + return 1; +} + + + +/** + * omap3_mmc_intr - interrupt handler for MMC/SD/SDIO controller + * @arg: pointer to the driver context + * + * Interrupt handler for the MMC/SD/SDIO controller, responsible for handling + * the IRQ and clearing the status flags. + * + * LOCKING: + * Called from interrupt context + * + * RETURNS: + * nothing + */ +static void +omap3_mmc_intr(void *arg) +{ + struct omap3_mmc_softc *sc = (struct omap3_mmc_softc *) arg; + uint32_t stat_reg; + int done = 0; + + + OMAP3_MMC_LOCK(sc); + + stat_reg = omap3_mmc_readl(sc, OMAP35XX_MMCHS_STAT) + & (omap3_mmc_readl(sc, OMAP35XX_MMCHS_IE) | MMCHS_STAT_ERRI); + + + if (stat_reg & MMCHS_STAT_ERRI) { + /* An error has been tripped in the status register */ + done = omap3_mmc_intr_error(sc, sc->curcmd, stat_reg); + + } else { + + /* NOTE: This implementation could be a bit inefficent, I don't think + * it is necessary to handle both the 'command complete' and 'transfer + * complete' for data transfers ... presumably just transfer complete + * is enough. + */ + + /* No error */ + sc->curcmd->error = MMC_ERR_NONE; + + /* Check if the command completed */ + if (stat_reg & MMCHS_STAT_CC) { + done = omap3_mmc_intr_cmd_compl(sc, sc->curcmd); + } + + /* Check if the transfer has completed */ + if (stat_reg & MMCHS_STAT_TC) { + done = omap3_mmc_intr_xfer_compl(sc, sc->curcmd); + } + + } + + /* Clear all the interrupt status bits by writing the value back */ + omap3_mmc_writel(sc, OMAP35XX_MMCHS_STAT, stat_reg); + + + /* This may mark the command as done if there is no stop request */ + /* TODO: This is a bit ugly, needs fix-up */ + if (done) { + omap3_mmc_start(sc); + } + + OMAP3_MMC_UNLOCK(sc); +} + + + +/** + * omap3_mmc_start_cmd - starts the given command + * @sc: pointer to the driver context + * @cmd: the command to start + * + * The call tree for this function is + * - omap3_mmc_start_cmd + * - omap3_mmc_start + * - omap3_mmc_request + * + * LOCKING: + * Caller should be holding the OMAP3_MMC lock. + * + * RETURNS: + * nothing + */ +static void +omap3_mmc_start_cmd(struct omap3_mmc_softc *sc, struct mmc_command *cmd) +{ + uint32_t cmd_reg, con_reg, ise_reg; + struct mmc_data *data; + struct mmc_request *req; + void *vaddr; + bus_addr_t paddr; + uint32_t pktsize; + + + sc->curcmd = cmd; + data = cmd->data; + req = cmd->mrq; + + /* By default no bits should be set for the CON register */ + con_reg = 0x0; + + /* Load the command into bits 29:24 of the CMD register */ + cmd_reg = (uint32_t)(cmd->opcode & 0x3F) << 24; + + /* Set the default set of interrupts */ + ise_reg = (MMCHS_STAT_CERR | MMCHS_STAT_CTO | MMCHS_STAT_CC | MMCHS_STAT_CEB); + + /* Enable CRC checking if requested */ + if (cmd->flags & MMC_RSP_CRC) + ise_reg |= MMCHS_STAT_CCRC; + + /* Enable reply index checking if the response supports it */ + if (cmd->flags & MMC_RSP_OPCODE) + ise_reg |= MMCHS_STAT_CIE; + + + /* Set the expected response length */ + if (MMC_RSP(cmd->flags) == MMC_RSP_NONE) { + cmd_reg |= MMCHS_CMD_RSP_TYPE_NO; + } else { + if (cmd->flags & MMC_RSP_136) + cmd_reg |= MMCHS_CMD_RSP_TYPE_136; + else if (cmd->flags & MMC_RSP_BUSY) + cmd_reg |= MMCHS_CMD_RSP_TYPE_48_BSY; + else + cmd_reg |= MMCHS_CMD_RSP_TYPE_48; + + /* Enable command index/crc checks if necessary expected */ + if (cmd->flags & MMC_RSP_CRC) + cmd_reg |= MMCHS_CMD_CCCE; + if (cmd->flags & MMC_RSP_OPCODE) + cmd_reg |= MMCHS_CMD_CICE; + } + + /* Set the bits for the special commands CMD12 (MMC_STOP_TRANSMISSION) and + * CMD52 (SD_IO_RW_DIRECT) */ + if (cmd->opcode == MMC_STOP_TRANSMISSION) + cmd_reg |= MMCHS_CMD_CMD_TYPE_IO_ABORT; + + /* Put the controller in open drain mode */ + if (sc->host.ios.bus_mode == opendrain) + con_reg |= MMCHS_CON_OD; + + /* Check if there is any data to write */ + if (data == NULL) { + + /* The no data case is fairly simple */ + omap3_mmc_writel(sc, OMAP35XX_MMCHS_CON, con_reg); + omap3_mmc_writel(sc, OMAP35XX_MMCHS_IE, ise_reg); + omap3_mmc_writel(sc, OMAP35XX_MMCHS_ISE, ise_reg); + omap3_mmc_writel(sc, OMAP35XX_MMCHS_ARG, cmd->arg); + omap3_mmc_writel(sc, OMAP35XX_MMCHS_CMD, cmd_reg); + return; + } + + /* Indicate that data is present */ + cmd_reg |= MMCHS_CMD_DP | MMCHS_CMD_MSBS | MMCHS_CMD_BCE; + + /* Indicate a read operation */ + if (data->flags & MMC_DATA_READ) + cmd_reg |= MMCHS_CMD_DDIR; + + + //if (data->flags & (MMC_DATA_READ | MMC_DATA_WRITE)) + // cmd_reg |= MCI_CMDR_TRCMD_START; + + /* Streaming mode */ + if (data->flags & MMC_DATA_STREAM) { + con_reg |= MMCHS_CON_STR; + } + + /* Multi-block mode */ + if (data->flags & MMC_DATA_MULTI) { + cmd_reg |= MMCHS_CMD_MSBS; + } + + + /* Enable extra interrupt sources for the transfer */ + ise_reg |= (MMCHS_STAT_TC | MMCHS_STAT_DTO | MMCHS_STAT_DEB | MMCHS_STAT_CEB); + if (cmd->flags & MMC_RSP_CRC) + ise_reg |= MMCHS_STAT_DCRC; + + /* Enable the DMA transfer bit */ + cmd_reg |= MMCHS_CMD_DE; + + /* Set the block size and block count */ + omap3_mmc_writel(sc, OMAP35XX_MMCHS_BLK, (1 << 16) | data->len); + + + + /* Setup the DMA stuff */ + if (data->flags & (MMC_DATA_READ | MMC_DATA_WRITE)) { + + vaddr = data->data; + data->xfer_len = 0; + + /* Map the buffer buf into bus space using the dmamap map. */ + if (bus_dmamap_load(sc->sc_dmatag, sc->sc_dmamap, vaddr, data->len, + omap3_mmc_getaddr, &paddr, 0) != 0) { + + if (req->cmd->flags & STOP_STARTED) + req->stop->error = MMC_ERR_NO_MEMORY; + else + req->cmd->error = MMC_ERR_NO_MEMORY; + sc->req = NULL; + sc->curcmd = NULL; + req->done(req); + return; + } + + + /* Calculate the packet size, the max packet size is 512 bytes + * (or 128 32-bit elements). + */ + pktsize = min((data->len / 4), (512 / 4)); + + /* Sync the DMA buffer and setup the DMA controller */ + if (data->flags & MMC_DATA_READ) { + bus_dmamap_sync(sc->sc_dmatag, sc->sc_dmamap, BUS_DMASYNC_PREREAD); + omap3_dma_start_xfer_packet(sc->sc_dmach_rd, + (OMAP35XX_MMCHS1_HWBASE + OMAP35XX_MMCHS_DATA), + paddr, 1, (data->len / 4), pktsize); + } else { + bus_dmamap_sync(sc->sc_dmatag, sc->sc_dmamap, BUS_DMASYNC_PREWRITE); + omap3_dma_start_xfer_packet(sc->sc_dmach_wr, paddr, + (OMAP35XX_MMCHS1_HWBASE + OMAP35XX_MMCHS_DATA), + 1, (data->len / 4), pktsize); + } + + /* Increase the mapped count */ + sc->sc_dmamapped++; + + sc->sc_cmd_data_vaddr = vaddr; + sc->sc_cmd_data_len = data->len; + } + +/* + printf("MMCHS_CON 0x%08x\n", con_reg); + printf("MMCHS_IE 0x%08x\n", ise_reg); + printf("MMCHS_ISE 0x%08x\n", ise_reg); + printf("MMCHS_CMD 0x%08x\n", cmd_reg); // 0x123a0033 + printf("MMCHS_ARG 0x%08x\n", cmd->arg); + printf("MMCHS_BLK 0x%08x\n", omap3_mmc_readl(sc, OMAP35XX_MMCHS_BLK)); + printf("MMCHS_PSTATE 0x%08x\n", omap3_mmc_readl(sc, OMAP35XX_MMCHS_PSTATE)); +*/ + + /* Finally kick off the command */ + omap3_mmc_writel(sc, OMAP35XX_MMCHS_CON, con_reg); + omap3_mmc_writel(sc, OMAP35XX_MMCHS_IE, ise_reg); + omap3_mmc_writel(sc, OMAP35XX_MMCHS_ISE, ise_reg); + omap3_mmc_writel(sc, OMAP35XX_MMCHS_ARG, cmd->arg); + omap3_mmc_writel(sc, OMAP35XX_MMCHS_CMD, cmd_reg); + + /* and we're done */ +} + + + + +/** + * omap3_mmc_start - starts a request stored in the driver context + * @sc: pointer to the driver context + * + * This function is called by omap3_mmc_request() in response to a read/write + * request from the MMC core module. + * + * LOCKING: + * Caller should be holding the OMAP3_MMC lock. + * + * RETURNS: + * nothing + */ +static void +omap3_mmc_start(struct omap3_mmc_softc *sc) +{ + struct mmc_request *req; + + + /* Sanity check we have a request */ + req = sc->req; + if (req == NULL) + return; + + /* assert locked */ + if (!(sc->flags & CMD_STARTED)) { + sc->flags |= CMD_STARTED; + omap3_mmc_start_cmd(sc, req->cmd); + return; + } + + if (!(sc->flags & STOP_STARTED) && req->stop) { + sc->flags |= STOP_STARTED; + omap3_mmc_start_cmd(sc, req->stop); + return; + } + + /* We must be done -- bad idea to do this while locked? */ + sc->req = NULL; + sc->curcmd = NULL; + req->done(req); +} + + + +/** + * omap3_mmc_request - entry point for all read/write/cmd requests + * @brdev: mmc bridge device handle + * @reqdev: the device doing the requesting ? + * @req: the action requested + * + * LOCKING: + * None, internally takes the OMAP3_MMC lock. + * + * RETURNS: + * 0 on success + * EBUSY if the driver is already performing a request + */ +static int +omap3_mmc_request(device_t brdev, device_t reqdev, struct mmc_request *req) +{ + struct omap3_mmc_softc *sc = device_get_softc(brdev); + + + OMAP3_MMC_LOCK(sc); + + // XXX do we want to be able to queue up multiple commands? + // XXX sounds like a good idea, but all protocols are sync, so + // XXX maybe the idea is naive... + if (sc->req != NULL) { + OMAP3_MMC_UNLOCK(sc); + return (EBUSY); + } + + /* Store the request and start the command */ + sc->req = req; + sc->flags = 0; + omap3_mmc_start(sc); + + OMAP3_MMC_UNLOCK(sc); + + return (0); +} + + +/** + * omap3_mmc_get_ro - returns the status of the read-only setting + * @brdev: mmc bridge device handle + * @reqdev: device doing the request + * + * This function is relies on hint'ed values to determine which GPIO is used + * to determine if the write protect is enabled. On the BeagleBoard the pin + * is GPIO_23. + * + * LOCKING: + * - + * + * RETURNS: + * 0 if not read-only + * 1 if read only + */ +static int +omap3_mmc_get_ro(device_t brdev, device_t reqdev) +{ + struct omap3_mmc_softc *sc = device_get_softc(brdev); + int readonly = 0; + + OMAP3_MMC_LOCK(sc); + + if (sc->sc_wp_gpio_pin != -1) { + readonly = (omap3_gpio_pin_get(sc->sc_wp_gpio_pin) == 0) ? 0 : 1; + + } + + OMAP3_MMC_UNLOCK(sc); + + + return (readonly); +} + + + +/** + * omap3_mmc_update_ios - sets bus/controller settings + * @brdev: mmc bridge device handle + * @reqdev: device doing the request + * + * Called to set the bus and controller settings that need to be applied to + * the actual HW. Currently this function just sets the bus width and the + * clock speed. + * + * LOCKING: + * + * + * RETURNS: + * 0 if function succeeded + */ +static int +omap3_mmc_update_ios(device_t brdev, device_t reqdev) +{ + struct omap3_mmc_softc *sc; + struct mmc_host *host; + struct mmc_ios *ios; + uint32_t clkdiv; + uint32_t hctl_reg; + uint32_t sysctl_reg; + + sc = device_get_softc(brdev); + host = &sc->host; + ios = &host->ios; + + + /* need the MMCHS_SYSCTL register */ + sysctl_reg = omap3_mmc_readl(sc, OMAP35XX_MMCHS_SYSCTL); + + /* Just in case this hasn't been setup before, set the timeout to the default */ + sysctl_reg &= MMCHS_SYSCTL_DTO_MASK; + sysctl_reg |= MMCHS_SYSCTL_DTO(0xe); + + /* Disable the clock output while configuring the new clock */ + sysctl_reg &= ~(MMCHS_SYSCTL_ICE | MMCHS_SYSCTL_CEN); + omap3_mmc_writel(sc, OMAP35XX_MMCHS_SYSCTL, sysctl_reg); + + /* bus mode? */ + if (ios->clock == 0) { + clkdiv = 0; + } else { + clkdiv = OMAP3_MMC_REF_CLK / ios->clock; + if (clkdiv < 1) + clkdiv = 1; + if ((OMAP3_MMC_REF_CLK / clkdiv) > ios->clock) + clkdiv += 1; + if (clkdiv > 250) + clkdiv = 250; + } + + /* Set the new clock divider */ + sysctl_reg &= ~MMCHS_SYSCTL_CLKD_MASK; + sysctl_reg |= MMCHS_SYSCTL_CLKD(clkdiv); + + /* Write the new settings ... */ + omap3_mmc_writel(sc, OMAP35XX_MMCHS_SYSCTL, sysctl_reg); + /* ... write the internal clock enable bit ... */ + omap3_mmc_writel(sc, OMAP35XX_MMCHS_SYSCTL, sysctl_reg | MMCHS_SYSCTL_ICE); + /* ... wait for the clock to stablise ... */ + while (((sysctl_reg = omap3_mmc_readl(sc, OMAP35XX_MMCHS_SYSCTL)) & + MMCHS_SYSCTL_ICS) == 0) { + continue; + } + /* ... then enable */ + sysctl_reg |= MMCHS_SYSCTL_CEN; + omap3_mmc_writel(sc, OMAP35XX_MMCHS_SYSCTL, sysctl_reg); + + + /* Set the bus width */ + hctl_reg = omap3_mmc_readl(sc, OMAP35XX_MMCHS_HCTL); + if (ios->bus_width == bus_width_4) + hctl_reg |= MMCHS_HCTL_DTW; + else + hctl_reg &= ~MMCHS_HCTL_DTW; + omap3_mmc_writel(sc, OMAP35XX_MMCHS_HCTL, hctl_reg); + + + return (0); +} + + +/** + * omap3_mmc_acquire_host - + * @brdev: mmc bridge device handle + * @reqdev: device doing the request + * + * TODO: Is this function needed ? + * + * LOCKING: + * none + * + * RETURNS: + * 0 function succeeded + * + */ +static int +omap3_mmc_acquire_host(device_t brdev, device_t reqdev) +{ + struct omap3_mmc_softc *sc = device_get_softc(brdev); + int err = 0; + + OMAP3_MMC_LOCK(sc); + + while (sc->bus_busy) { + msleep(sc, &sc->sc_mtx, PZERO, "mmc", hz / 5); + } + + sc->bus_busy++; + + OMAP3_MMC_UNLOCK(sc); + + return (err); +} + +/** + * omap3_mmc_release_host - + * @brdev: mmc bridge device handle + * @reqdev: device doing the request + * + * TODO: Is this function needed ? + * + * LOCKING: + * none + * + * RETURNS: + * 0 function succeeded + * + */ +static int +omap3_mmc_release_host(device_t brdev, device_t reqdev) +{ + struct omap3_mmc_softc *sc = device_get_softc(brdev); + + OMAP3_MMC_LOCK(sc); + + sc->bus_busy--; + wakeup(sc); + + OMAP3_MMC_UNLOCK(sc); + + return (0); +} + + + + +/** + * omap3_mmc_read_ivar - returns driver conf variables + * @bus: + * @child: + * @which: The variable to get the result for + * @result: Upon return will store the variable value + * + * + * + * LOCKING: + * None, caller must hold locks + * + * RETURNS: + * 0 on success + * EINVAL if the variable requested is invalid + */ +static int +omap3_mmc_read_ivar(device_t bus, device_t child, int which, uintptr_t *result) +{ + struct omap3_mmc_softc *sc = device_get_softc(bus); + + switch (which) { + case MMCBR_IVAR_BUS_MODE: + *(int *)result = sc->host.ios.bus_mode; + break; + case MMCBR_IVAR_BUS_WIDTH: + *(int *)result = sc->host.ios.bus_width; + break; + case MMCBR_IVAR_CHIP_SELECT: + *(int *)result = sc->host.ios.chip_select; + break; + case MMCBR_IVAR_CLOCK: + *(int *)result = sc->host.ios.clock; + break; + case MMCBR_IVAR_F_MIN: + *(int *)result = sc->host.f_min; + break; + case MMCBR_IVAR_F_MAX: + *(int *)result = sc->host.f_max; + break; + case MMCBR_IVAR_HOST_OCR: + *(int *)result = sc->host.host_ocr; + break; + case MMCBR_IVAR_MODE: + *(int *)result = sc->host.mode; + break; + case MMCBR_IVAR_OCR: + *(int *)result = sc->host.ocr; + break; + case MMCBR_IVAR_POWER_MODE: + *(int *)result = sc->host.ios.power_mode; + break; + case MMCBR_IVAR_VDD: + *(int *)result = sc->host.ios.vdd; + break; + case MMCBR_IVAR_CAPS: + *(int *)result = sc->host.caps; + break; + case MMCBR_IVAR_MAX_DATA: + *(int *)result = 1; + break; + default: + return (EINVAL); + } + return (0); +} + + +/** + * omap3_mmc_write_ivar - writes a driver conf variables + * @bus: + * @child: + * @which: The variable to set + * @value: The value to write into the variable + * + * + * + * LOCKING: + * None, caller must hold locks + * + * RETURNS: + * 0 on success + * EINVAL if the variable requested is invalid + */ +static int +omap3_mmc_write_ivar(device_t bus, device_t child, int which, uintptr_t value) +{ + struct omap3_mmc_softc *sc = device_get_softc(bus); + + switch (which) { + case MMCBR_IVAR_BUS_MODE: + sc->host.ios.bus_mode = value; + break; + case MMCBR_IVAR_BUS_WIDTH: + sc->host.ios.bus_width = value; + break; + case MMCBR_IVAR_CHIP_SELECT: + sc->host.ios.chip_select = value; + break; + case MMCBR_IVAR_CLOCK: + sc->host.ios.clock = value; + break; + case MMCBR_IVAR_MODE: + sc->host.mode = value; + break; + case MMCBR_IVAR_OCR: + sc->host.ocr = value; + break; + case MMCBR_IVAR_POWER_MODE: + sc->host.ios.power_mode = value; + break; + case MMCBR_IVAR_VDD: + sc->host.ios.vdd = value; + break; + /* These are read-only */ + case MMCBR_IVAR_CAPS: + case MMCBR_IVAR_HOST_OCR: + case MMCBR_IVAR_F_MIN: + case MMCBR_IVAR_F_MAX: + case MMCBR_IVAR_MAX_DATA: + return (EINVAL); + default: + return (EINVAL); + } + return (0); +} + + + + +static device_method_t g_omap3_mmc_methods[] = { + /* device_if */ + DEVMETHOD(device_probe, omap3_mmc_probe), + DEVMETHOD(device_attach, omap3_mmc_attach), + DEVMETHOD(device_detach, omap3_mmc_detach), + + /* Bus interface */ + DEVMETHOD(bus_read_ivar, omap3_mmc_read_ivar), + DEVMETHOD(bus_write_ivar, omap3_mmc_write_ivar), + + /* mmcbr_if - MMC state machine callbacks */ + DEVMETHOD(mmcbr_update_ios, omap3_mmc_update_ios), + DEVMETHOD(mmcbr_request, omap3_mmc_request), + DEVMETHOD(mmcbr_get_ro, omap3_mmc_get_ro), + DEVMETHOD(mmcbr_acquire_host, omap3_mmc_acquire_host), + DEVMETHOD(mmcbr_release_host, omap3_mmc_release_host), + + {0, 0}, +}; + +static driver_t g_omap3_mmc_driver = { + "omap3_mmc", + g_omap3_mmc_methods, + sizeof(struct omap3_mmc_softc), +}; +static devclass_t g_omap3_mmc_devclass; + + +DRIVER_MODULE(omap3_mmc, omap3, g_omap3_mmc_driver, g_omap3_mmc_devclass, 0, 0); +MODULE_DEPEND(omap3_mmc, omap3_prcm, 1, 1, 1); +MODULE_DEPEND(omap3_mmc, omap3_dma, 1, 1, 1); +MODULE_DEPEND(omap3_mmc, omap3_scm, 1, 1, 1); +MODULE_DEPEND(omap3_mmc, omap3_gpio, 1, 1, 1); + Index: sys/arm/cortexa8/omap3/omap3_i2c.c =================================================================== --- sys/arm/cortexa8/omap3/omap3_i2c.c (revision 0) +++ sys/arm/cortexa8/omap3/omap3_i2c.c (revision 0) @@ -0,0 +1,1181 @@ +/* + * Copyright (c) 2010 + * Ben Gray . + * All rights reserved. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Ben Gray. + * 4. The name of the company nor the name of the author may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY BEN GRAY ``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 BEN GRAY 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. + */ + +/** + * Driver for the I2C module on the TI OMAP3530 SoC. + * + * This driver is heavily based on the TWI driver for the AT91 (at91_twi.c). + * + * The OMAP3530 has 3 I2C controllers, hints are used to indicate which devices + * to enable. + * + * CAUTION: The I2Ci registers are limited to 16 bit and 8 bit data accesses, + * 32 bit data access is not allowed and can corrupt register content. + * + * This driver currently doesn't use DMA for the transfer, although I hope to + * incorporate that sometime in the future. The idea being that for transaction + * larger than a certain size the DMA engine is used, for anything less the + * normal interrupt/fifo driven option is used. + * + * + * WARNING: This driver uses mtx_sleep and interrupts to perform transactions, + * which means you can't do a transaction during startup before the interrupts + * have been enabled. Hint - the freebsd function config_intrhook_establish(). + */ + + + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include "iicbus_if.h" + + + + +/** + * I2C device driver context, a pointer to this is stored in the device + * driver structure. + */ +struct omap3_i2c_softc +{ + device_t sc_dev; + unsigned int sc_controller; /* the controller number; 1, 2 or 3 */ + bus_space_tag_t sc_iotag; + bus_space_handle_t sc_ioh; + + device_t sc_iicbus; + + void* sc_irq_h; + struct resource* sc_irq_res; /* IRQ resource */ + + struct mtx sc_mtx; + + volatile uint16_t sc_stat_flags; /* contains the status flags last IRQ */ + + uint16_t sc_i2c_addr; +}; + + +/** + * omap3_i2c_readw - reads a 16-bit value from one of the I2C registers + * @sc: I2C device context + * @off: the byte offset within the register bank to read from. + * + * + * LOCKING: + * No locking required + * + * RETURNS: + * 16-bit value read from the register. + */ +static inline uint16_t +omap3_i2c_readw(struct omap3_i2c_softc *sc, bus_size_t off) +{ + return bus_space_read_2(sc->sc_iotag, sc->sc_ioh, off); +} + +/** + * omap3_i2c_writew - writes a 16-bit value to one of the I2C registers + * @sc: I2C device context + * @off: the byte offset within the register bank to read from. + * @val: the value to write into the register + * + * LOCKING: + * No locking required + * + * RETURNS: + * 16-bit value read from the register. + */ +static inline void +omap3_i2c_writew(struct omap3_i2c_softc *sc, bus_size_t off, uint16_t val) +{ + bus_space_write_2(sc->sc_iotag, sc->sc_ioh, off, val); +} + + +/** + * Locking macros used throughout the driver + */ +#define OMAP3_I2C_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) +#define OMAP3_I2C_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) +#define OMAP3_I2C_LOCK_INIT(_sc) \ + mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), \ + "omap3_i2c", MTX_DEF) +#define OMAP3_I2C_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx); +#define OMAP3_I2C_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED); +#define OMAP3_I2C_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED); + + +static devclass_t omap3_i2c_devclass; + +/* bus entry points */ + +static int omap3_i2c_probe(device_t dev); +static int omap3_i2c_attach(device_t dev); +static int omap3_i2c_detach(device_t dev); +static void omap3_i2c_intr(void *); + +/* helper routines */ +static int omap3_i2c_activate(device_t dev); +static void omap3_i2c_deactivate(device_t dev); + + + + + + +/** + * omap3_i2c_probe - probe function for the driver + * @dev: i2c device handle + * + * + * + * LOCKING: + * + * + * RETURNS: + * Always returns 0 + */ +static int +omap3_i2c_probe(device_t dev) +{ + device_set_desc(dev, "TI OMAP3530 I2C Controller"); + return (0); +} + + +/** + * omap3_i2c_attach - attach function for the driver + * @dev: i2c device handle + * + * Initialised driver data structures and activates the I2C controller. + * + * LOCKING: + * + * + * RETURNS: + * + */ +static int +omap3_i2c_attach(device_t dev) +{ + struct omap3_i2c_softc *sc = device_get_softc(dev); + int err; + + sc->sc_dev = dev; + sc->sc_iotag = &omap3_bs_tag; + + /* TODO: figure out how to have multiple I2C bus controllers */ + + /* for now we only use controller 1 */ + sc->sc_controller = 1; + + err = omap3_i2c_activate(dev); + if (err) + goto out; + + OMAP3_I2C_LOCK_INIT(sc); + + /* activate the interrupt */ + err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_MISC | INTR_MPSAFE, + NULL, omap3_i2c_intr, sc, &sc->sc_irq_h); + if (err) { + OMAP3_I2C_LOCK_DESTROY(sc); + goto out; + } + + if ((sc->sc_iicbus = device_add_child(dev, "iicbus", -1)) == NULL) + device_printf(dev, "could not allocate iicbus instance\n"); + + /* probe and attach the iicbus */ + bus_generic_attach(dev); + + +out: + if (err) + omap3_i2c_deactivate(dev); + return (err); +} + + + +/** + * omap3_i2c_detach - detach function for the driver + * @dev: i2c device handle + * + * + * + * LOCKING: + * + * + * RETURNS: + * Always returns 0 + */ +static int +omap3_i2c_detach(device_t dev) +{ + struct omap3_i2c_softc *sc = device_get_softc(dev); + int rv; + + omap3_i2c_deactivate(dev); + + if (sc->sc_iicbus && (rv = device_delete_child(dev, sc->sc_iicbus)) != 0) + return (rv); + + OMAP3_I2C_LOCK_DESTROY(sc); + + return (0); +} + + +/** + * omap3_i2c_activate - initialises and activates an I2C bus + * @dev: i2c device handle + * @num: the number of the I2C controller to activate; 1, 2 or 3 + * + * + * LOCKING: + * Assumed called in an atomic context. + * + * RETURNS: + * nothing + */ +static int +omap3_i2c_activate(device_t dev) +{ + struct omap3_i2c_softc *sc = (struct omap3_i2c_softc*) device_get_softc(dev); + unsigned int timeout = 0; + int err = ENOMEM; + int rid = 0; + uint32_t membase; + uint32_t memsize; + uint32_t irqnum; + uint32_t iclk; + uint32_t fclk; + uint16_t con_reg; + + + /* Sort out the IRQ, memory addresses and clocks for the controller */ + switch (sc->sc_controller) { + case 1: + membase = OMAP35XX_I2C1_HWBASE; + memsize = OMAP35XX_I2C1_SIZE; + irqnum = OMAP35XX_IRQ_I2C1; + iclk = OMAP3_MODULE_I2C1_ICLK; + fclk = OMAP3_MODULE_I2C1_FCLK; + break; + case 2: + membase = OMAP35XX_I2C2_HWBASE; + memsize = OMAP35XX_I2C2_SIZE; + irqnum = OMAP35XX_IRQ_I2C2; + iclk = OMAP3_MODULE_I2C2_ICLK; + fclk = OMAP3_MODULE_I2C2_FCLK; + break; + case 3: + membase = OMAP35XX_I2C3_HWBASE; + memsize = OMAP35XX_I2C3_SIZE; + irqnum = OMAP35XX_IRQ_I2C3; + iclk = OMAP3_MODULE_I2C3_ICLK; + fclk = OMAP3_MODULE_I2C3_FCLK; + break; + default: + return(-EINVAL); + } + + /* Map the register set for the I2C controller */ + if (bus_space_map(sc->sc_iotag, membase, memsize, 0, &sc->sc_ioh)) { + panic("%s: Cannot map registers", device_get_name(dev)); + sc->sc_ioh = 0; + } + + + /* Allocate an IRQ resource for the I2C controller */ + sc->sc_irq_res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, irqnum, irqnum, + 1, RF_ACTIVE); + if (sc->sc_irq_res == NULL) { + err = -ENOMEM; + goto errout; + } + + /* + * The following sequence is taken from the OMAP3530 technical reference + * + * 1. Enable the functional and interface clocks (see Section 18.3.1.1.1). + */ + + /* Set the EN_I2C1 bit (I2C 1 interface clock control) */ + omap3_prcm_enable_clk(iclk); + + /* Set the EN_I2C1 bit (I2C 1 functional clock control) */ + omap3_prcm_enable_clk(fclk); + + /* There seems to be a bug in the I2C reset mechanism, for some reason you + * need to disable the I2C module before issuing the reset and then enable + * it again after to detect the reset done. + * + * I found this out by looking at the Linux driver implementation, thanks + * linux guys! + */ + + /* Disable the I2C controller */ + omap3_i2c_writew(sc, OMAP35XX_I2C_CON, 0x0000); + + /* Issue a softreset to the controller */ + omap3_i2c_writew(sc, OMAP35XX_I2C_SYSC, 0x0002); + + /* Re-enable the module and then check for the reset done */ + omap3_i2c_writew(sc, OMAP35XX_I2C_CON, I2C_CON_I2C_EN); + + while ((omap3_i2c_readw(sc, OMAP35XX_I2C_SYSS) & 0x01) == 0x00) { + if (timeout++ > 100) { + err = -EBUSY; + goto errout; + } + DELAY(100); + } + + /* Disable the I2C controller once again, now that the reset has finished */ + omap3_i2c_writew(sc, OMAP35XX_I2C_CON, 0x0000); + + + + /* 2. Program the prescaler to obtain an approximately 12-MHz internal + * sampling clock (I2Ci_INTERNAL_CLK) by programming the corresponding + * value in the I2Ci.I2C_PSC[3:0] PSC field. + * This value depends on the frequency of the functional clock (I2Ci_FCLK). + * Because this frequency is 96MHz, the I2Ci.I2C_PSC[7:0] PSC field value + * is 0x7. + */ + + /* Program the prescaler to obtain an approximately 12-MHz internal + * sampling clock. + */ + omap3_i2c_writew(sc, OMAP35XX_I2C_PSC, 0x0017); + + + /* 3. Program the I2Ci.I2C_SCLL[7:0] SCLL and I2Ci.I2C_SCLH[7:0] SCLH fields + * to obtain a bit rate of 100K bps or 400K bps. These values depend on + * the internal sampling clock frequency (see Table 18-12). + */ + + /* Set the bitrate to 100kbps */ + omap3_i2c_writew(sc, OMAP35XX_I2C_SCLL, 0x000d); + omap3_i2c_writew(sc, OMAP35XX_I2C_SCLH, 0x000f); + + + /* 4. (Optional) Program the I2Ci.I2C_SCLL[15:8] HSSCLL and + * I2Ci.I2C_SCLH[15:8] HSSCLH fields to obtain a bit rate of 400K bps or + * 3.4M bps (for the second phase of HS mode). These values depend on the + * internal sampling clock frequency (see Table 18-12). + * + * 5. (Optional) If a bit rate of 3.4M bps is used and the bus line + * capacitance exceeds 45 pF, program the CONTROL.CONTROL_DEVCONF1[12] + * I2C1HSMASTER bit for I2C1, the CONTROL.CONTROL_DEVCONF1[13] + * I2C2HSMASTER bit for I2C2, or the CONTROL.CONTROL_DEVCONF1[14] + * I2C3HSMASTER bit for I2C3. + */ + + + /* 6. Configure the Own Address of the I2C controller by storing it in the + * I2Ci.I2C_OA0 register. Up to four Own Addresses can be programmed in + * the I2Ci.I2C_OAi registers (with I = 0, 1, 2, 3) for each I2C + * controller. + * + * Note: For a 10-bit address, set the corresponding expand Own Address bit + * in the I2Ci.I2C_CON register. + */ + + /* Driver currently always in single master mode so ignore this step */ + + + + /* 7. Set the TX threshold (in transmitter mode) and the RX threshold (in + * receiver mode) by setting the I2Ci.I2C_BUF[5:0]XTRSH field to (TX + * threshold - 1) and the I2Ci.I2C_BUF[13:8]RTRSH field to (RX threshold + * - 1), where the TX and RX thresholds are greater than or equal to 1. + */ + + /* Set the FIFO buffer threshold, note I2C1 & I2C2 have 8 byte FIFO, whereas + * I2C3 has 64 bytes. Threshold set to 5 for now. + */ + omap3_i2c_writew(sc, OMAP35XX_I2C_BUF, 0x0404); + + + /* + * 8. Take the I2C controller out of reset by setting the I2Ci.I2C_CON[15] + * I2C_EN bit to 1. + */ + omap3_i2c_writew(sc, OMAP35XX_I2C_CON, I2C_CON_I2C_EN | I2C_CON_OPMODE_STD); + + + + /* + * To initialize the I2C controller, perform the following steps: + * + * 1. Configure the I2Ci.I2C_CON register: + * · For master or slave mode, set the I2Ci.I2C_CON[10] MST bit (0: slave, + * 1: master). + * · For transmitter or receiver mode, set the I2Ci.I2C_CON[9] TRX bit + * (0: receiver, 1: transmitter). + */ + con_reg = omap3_i2c_readw(sc, OMAP35XX_I2C_CON); + con_reg |= I2C_CON_MST; + omap3_i2c_writew(sc, OMAP35XX_I2C_CON, con_reg); + + + /* 2. If using an interrupt to transmit/receive data, set to 1 the + * corresponding bit in the I2Ci.I2C_IE register (the I2Ci.I2C_IE[4] + * XRDY_IE bit for the transmit interrupt, the I2Ci.I2C_IE[3] RRDY bit + * for the receive interrupt). + */ + omap3_i2c_writew(sc, OMAP35XX_I2C_IE, I2C_IE_XRDY | I2C_IE_RRDY); + + + /* 3. If using DMA to receive/transmit data, set to 1 the corresponding bit + * in the I2Ci.I2C_BUF register (the I2Ci.I2C_BUF[15] RDMA_EN bit for the + * receive DMA channel, the I2Ci.I2C_BUF[7] XDMA_EN bit for the transmit + * DMA channel). + */ + + /* not using DMA for now, so ignore this */ + + + return(0); + +errout: + return(err); +} + + +/** + * omap3_i2c_deactivate - deactivates the controller and releases resources + * @dev: i2c device handle + * + * + * + * LOCKING: + * Assumed called in an atomic context. + * + * RETURNS: + * nothing + */ +static void +omap3_i2c_deactivate(device_t dev) +{ + struct omap3_i2c_softc *sc = device_get_softc(dev); + uint32_t memsize; + uint32_t iclk; + uint32_t fclk; + + /* Sort out the IRQ, memory addresses and clocks for the controller */ + switch (sc->sc_controller) { + case 1: + memsize = OMAP35XX_I2C1_SIZE; + iclk = OMAP3_MODULE_I2C1_ICLK; + fclk = OMAP3_MODULE_I2C1_FCLK; + break; + case 2: + memsize = OMAP35XX_I2C2_SIZE; + iclk = OMAP3_MODULE_I2C2_ICLK; + fclk = OMAP3_MODULE_I2C2_FCLK; + break; + case 3: + memsize = OMAP35XX_I2C3_SIZE; + iclk = OMAP3_MODULE_I2C3_ICLK; + fclk = OMAP3_MODULE_I2C3_FCLK; + break; + default: + return; + } + + /* Disable the controller - cancel all transactions */ + omap3_i2c_writew(sc, OMAP35XX_I2C_CON, 0x0000); + + /* Release the interrupt handler */ + if (sc->sc_irq_h) { + bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_irq_h); + sc->sc_irq_h = 0; + } + + bus_generic_detach(sc->sc_dev); + + /* Unmap the I2C controller registers */ + if (sc->sc_ioh != 0) { + bus_space_unmap(sc->sc_iotag, sc->sc_ioh, memsize); + sc->sc_ioh = 0; + } + + /* Release the IRQ resource */ + if (sc->sc_irq_res != NULL) { + bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(sc->sc_irq_res), + sc->sc_irq_res); + sc->sc_irq_res = NULL; + } + + + /* Finally disable the functional and interface clocks */ + omap3_prcm_disable_clk(iclk); + omap3_prcm_disable_clk(fclk); + + + return; +} + + + +/** + * omap3_i2c_reset - attach function for the driver + * @dev: i2c device handle + * + * + * + * LOCKING: + * Called from timer context + * + * RETURNS: + * EH_HANDLED or EH_NOT_HANDLED + */ +static int +omap3_i2c_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr) +{ + struct omap3_i2c_softc *sc = device_get_softc(dev); + uint16_t psc_reg, scll_reg, sclh_reg, con_reg; + + + OMAP3_I2C_LOCK(sc); + + if (oldaddr) + *oldaddr = sc->sc_i2c_addr; + sc->sc_i2c_addr = addr; + + + /* The header file doesn't actual tell you what speeds should be used for + * the 3 possible settings, so I'm going to go with the usual: + * + * IIC_SLOW => 100kbps + * IIC_FAST => 400kbps + * IIC_FASTEST => 3.4Mbps + * + * I2Ci_INTERNAL_CLK = I2Ci_FCLK / (PSC + 1) + * I2Ci_INTERNAL_CLK = 96MHZ / (PSC + 1) + */ + switch (speed) { + case IIC_FASTEST: + psc_reg = 0x0004; + scll_reg = 0x0811; + sclh_reg = 0x0a13; + break; + + case IIC_FAST: + psc_reg = 0x0009; + scll_reg = 0x0005; + sclh_reg = 0x0007; + break; + + case IIC_SLOW: + case IIC_UNKNOWN: + default: + psc_reg = 0x0017; + scll_reg = 0x000D; + sclh_reg = 0x000F; + break; + } + + /* First disable the controller while changing the clocks */ + con_reg = omap3_i2c_readw(sc, OMAP35XX_I2C_CON); + omap3_i2c_writew(sc, OMAP35XX_I2C_CON, 0x0000); + + /* Program the prescaler */ + omap3_i2c_writew(sc, OMAP35XX_I2C_PSC, psc_reg); + + /* Set the bitrate */ + omap3_i2c_writew(sc, OMAP35XX_I2C_SCLL, scll_reg); + omap3_i2c_writew(sc, OMAP35XX_I2C_SCLH, sclh_reg); + + /* Set the remote slave address */ + omap3_i2c_writew(sc, OMAP35XX_I2C_SA, addr); + + + /* Enable the I2C module again */ + con_reg = I2C_CON_I2C_EN; + con_reg |= (speed == IIC_FASTEST) ? I2C_CON_OPMODE_HS : I2C_CON_OPMODE_STD; + omap3_i2c_writew(sc, OMAP35XX_I2C_CON, con_reg); + + + OMAP3_I2C_UNLOCK(sc); + + return 0; +} + + + +/** + * omap3_i2c_intr - interrupt handler for the I2C module + * @dev: i2c device handle + * + * + * + * LOCKING: + * Called from timer context + * + * RETURNS: + * EH_HANDLED or EH_NOT_HANDLED + */ +static void +omap3_i2c_intr(void *arg) +{ + struct omap3_i2c_softc *sc = (struct omap3_i2c_softc*) arg; + uint16_t status; + + status = omap3_i2c_readw(sc, OMAP35XX_I2C_STAT); + if (status == 0) + return; + + OMAP3_I2C_LOCK(sc); + + /* save the flags */ + sc->sc_stat_flags |= status; + + /* clear the status flags */ + omap3_i2c_writew(sc, OMAP35XX_I2C_STAT, status); + + /* wakeup the process the started the transaction */ + wakeup(sc); + + OMAP3_I2C_UNLOCK(sc); + + return; +} + + +/** + * omap3_i2c_wait - waits for the specific event to occur + * @sc: i2c driver context + * @flags: the event(s) to wait on, this is a bitmask of the I2C_STAT_??? flags + * @statp: if not null will contain the status flags upon return + * @timo: the number of ticks to wait + * + * + * + * LOCKING: + * The driver context must be locked before calling this function. Internally + * the function sleeps, releasing the lock as it does so, however the lock is + * always retaken before this function returns. + * + * RETURNS: + * 0 if the event(s) were tripped within timeout period + * -EBUSY if timedout waiting for the events + * -ENXIO if a NACK event was received + */ +static int +omap3_i2c_wait(struct omap3_i2c_softc *sc, uint16_t flags, uint16_t *statp, int timo) +{ + int waittime = timo; + int start_ticks = ticks; + int rc; + + + OMAP3_I2C_ASSERT_LOCKED(sc); + + /* check if the condition has already occured, the interrupt routine will + * clear the status flags. + */ + if ((sc->sc_stat_flags & flags) == 0) { + + /* condition(s) haven't occured so sleep on the IRQ */ + while (waittime > 0) { + + rc = mtx_sleep(sc, &sc->sc_mtx, 0, "I2Cwait", waittime); + if (rc == EWOULDBLOCK) { + /* timed-out, simply break out of the loop */ + break; + } else { + /* IRQ has been tripped, but need to sanity check we have the + * right events in the status flag. + */ + if ((sc->sc_stat_flags & flags) != 0) + break; + + /* event hasn't been tripped so wait some more */ + waittime -= (ticks - start_ticks); + start_ticks = ticks; + } + } + } + + /* copy the actual status bits */ + if (statp != NULL) + *statp = sc->sc_stat_flags; + + /* return the status found */ + if ((sc->sc_stat_flags & flags) != 0) + rc = 0; + else + rc = -EBUSY; + + /* clear the flags set by the interrupt handler */ + sc->sc_stat_flags = 0; + + return(rc); +} + + +/** + * omap3_i2c_wait_for_free_bus - waits for the bus to become free + * @sc: i2c driver context + * @timo: the time to wait for the bus to become free + * + * + * + * LOCKING: + * The driver context must be locked before calling this function. Internally + * the function sleeps, releasing the lock as it does so, however the lock is + * always taken before this function returns. + * + * RETURNS: + * 0 if the event(s) were tripped within timeout period + * -EBUSY if timedout waiting for the events + * -ENXIO if a NACK event was received + */ +static int +omap3_i2c_wait_for_free_bus(struct omap3_i2c_softc *sc, int timo) +{ + /* check if the bus is free, BB bit = 0 */ + if ((omap3_i2c_readw(sc, OMAP35XX_I2C_STAT) & I2C_STAT_BB) == 0) + return 0; + + /* enable bus free interrupts */ + omap3_i2c_writew(sc, OMAP35XX_I2C_IE, I2C_IE_BF); + + /* wait for the bus free interrupt to be tripped */ + return omap3_i2c_wait(sc, I2C_STAT_BF, NULL, timo); +} + + +/** + * omap3_i2c_read_bytes - attempts to perform a read operation + * @sc: i2c driver context + * @buf: buffer to hold the received bytes + * @len: the number of bytes to read + * + * This function assumes the slave address is already set + * + * LOCKING: + * The context lock should be held before calling this function + * + * RETURNS: + * 0 on function succeeded + * -EINVAL if invalid message is passed as an arg + */ +static int +omap3_i2c_read_bytes(struct omap3_i2c_softc *sc, uint8_t *buf, uint16_t len) +{ + int timo = (hz / 4); + int err = 0; + uint16_t con_reg; + uint16_t events; + uint16_t status; + uint32_t amount = 0; + uint32_t sofar = 0; + uint32_t i; + + /* wait for the bus to become free */ + err = omap3_i2c_wait_for_free_bus(sc, timo); + if (err != 0) + return(err); + + /* set the events to wait for */ + events = I2C_IE_RDR | /* Receive draining interrupt */ + I2C_IE_RRDY | /* Receive Data Ready interrupt */ + I2C_IE_ARDY | /* Register Access Ready interrupt */ + I2C_IE_NACK | /* No Acknowledgment interrupt */ + I2C_IE_AL; + + /* enable interrupts for the events we want*/ + omap3_i2c_writew(sc, OMAP35XX_I2C_IE, events); + + /* write the number of bytes to read */ + omap3_i2c_writew(sc, OMAP35XX_I2C_CNT, len); + + /* clear the write bit and initiate the read transaction. Setting the STT + * (start) bit initiates the transfer. + */ + con_reg = omap3_i2c_readw(sc, OMAP35XX_I2C_CON); + con_reg &= ~I2C_CON_TRX; + con_reg |= I2C_CON_MST | I2C_CON_STT | I2C_CON_STP; + omap3_i2c_writew(sc, OMAP35XX_I2C_CON, con_reg); + + + /* reading loop */ + while (1) { + + /* wait for an event */ + err = omap3_i2c_wait(sc, events, &status, timo); + if (err != 0) + break; + + /* check for the error conditions */ + if (status & I2C_STAT_NACK) { + /* no ACK from slave */ + printf("[BRG] %s : %d : NACK\n", __func__, __LINE__); + err = -ENXIO; + break; + } + if (status & I2C_STAT_AL) { + /* arbitration lost */ + printf("[BRG] %s : %d : Arbitration lost\n", __func__, __LINE__); + err = -ENXIO; + break; + } + + /* check if we have finished */ + if (status & I2C_STAT_ARDY) { + /* register access ready - transaction complete basically */ + printf("[BRG] %s : %d : ARDY transaction complete\n", __func__, __LINE__); + err = 0; + break; + } + + + + /* read some data */ + if (status & I2C_STAT_RDR) { + /* Receive draining interrupt - last data received */ + printf("[BRG] %s : %d : Receive draining interrupt\n", __func__, __LINE__); + + /* get the number of bytes in the FIFO */ + amount = omap3_i2c_readw(sc, OMAP35XX_I2C_BUFSTAT); + amount >>= 8; + amount &= 0x3f; + } + else if (status & I2C_STAT_RRDY) { + /* Receive data ready interrupt - enough data received */ + printf("[BRG] %s : %d : Receive data ready interrupt\n", __func__, __LINE__); + + /* get the number of bytes in the FIFO */ + amount = omap3_i2c_readw(sc, OMAP35XX_I2C_BUF); + amount >>= 8; + amount &= 0x3f; + amount += 1; + } + + /* sanity check we haven't overwritten the array */ + if ((sofar + amount) > len) { + printf("[BRG] %s : %d : to many bytes to read\n", __func__, __LINE__); + amount = (len - sofar); + } + + /* read the bytes from the fifo */ + for (i = 0; i < amount; i++) { + buf[sofar++] = (uint8_t)(omap3_i2c_readw(sc, OMAP35XX_I2C_DATA) & 0xff); + } + + /* attempt to clear the receive ready bits */ + omap3_i2c_writew(sc, OMAP35XX_I2C_STAT, I2C_STAT_RDR | I2C_STAT_RRDY); + } + + /* reset the registers regardless if there was an error or not */ + omap3_i2c_writew(sc, OMAP35XX_I2C_IE, 0x0000); + omap3_i2c_writew(sc, OMAP35XX_I2C_CON, I2C_CON_I2C_EN | I2C_CON_MST | I2C_CON_STP); + + return(err); +} + + +/** + * omap3_i2c_write_bytes - attempts to perform a read operation + * @sc: i2c driver context + * @buf: buffer containing the bytes to write + * @len: the number of bytes to write + * + * This function assumes the slave address is already set + * + * LOCKING: + * The context lock should be held before calling this function + * + * RETURNS: + * 0 on function succeeded + * -EINVAL if invalid message is passed as an arg + */ +static int +omap3_i2c_write_bytes(struct omap3_i2c_softc *sc, const uint8_t *buf, uint16_t len) +{ + int timo = (hz / 4); + int err = 0; + uint16_t con_reg; + uint16_t events; + uint16_t status; + uint32_t amount = 0; + uint32_t sofar = 0; + uint32_t i; + + + /* wait for the bus to become free */ + err = omap3_i2c_wait_for_free_bus(sc, timo); + if (err != 0) + return(err); + + + /* set the events to wait for */ + events = I2C_IE_XDR | /* Transmit draining interrupt */ + I2C_IE_XRDY | /* Transmit Data Ready interrupt */ + I2C_IE_ARDY | /* Register Access Ready interrupt */ + I2C_IE_NACK | /* No Acknowledgment interrupt */ + I2C_IE_AL; + + /* enable interrupts for the events we want*/ + omap3_i2c_writew(sc, OMAP35XX_I2C_IE, events); + + /* write the number of bytes to write */ + omap3_i2c_writew(sc, OMAP35XX_I2C_CNT, len); + + /* set the write bit and initiate the write transaction. Setting the STT + * (start) bit initiates the transfer. + */ + con_reg = omap3_i2c_readw(sc, OMAP35XX_I2C_CON); + con_reg |= I2C_CON_TRX | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP; + omap3_i2c_writew(sc, OMAP35XX_I2C_CON, con_reg); + + + /* writing loop */ + while (1) { + + /* wait for an event */ + err = omap3_i2c_wait(sc, events, &status, timo); + if (err != 0) + break; + + + /* check for the error conditions */ + if (status & I2C_STAT_NACK) { + /* no ACK from slave */ + printf("[BRG] %s : %d : NACK\n", __func__, __LINE__); + err = -ENXIO; + break; + } + if (status & I2C_STAT_AL) { + /* arbitration lost */ + printf("[BRG] %s : %d : Arbitration lost\n", __func__, __LINE__); + err = -ENXIO; + break; + } + + /* check if we have finished */ + if (status & I2C_STAT_ARDY) { + /* register access ready - transaction complete basically */ + printf("[BRG] %s : %d : ARDY transaction complete\n", __func__, __LINE__); + err = 0; + break; + } + + + + /* read some data */ + if (status & I2C_STAT_XDR) { + /* Receive draining interrupt - last data received */ + printf("[BRG] %s : %d : Transmit draining interrupt\n", __func__, __LINE__); + + /* get the number of bytes in the FIFO */ + amount = omap3_i2c_readw(sc, OMAP35XX_I2C_BUFSTAT); + amount &= 0x3f; + } + else if (status & I2C_STAT_XRDY) { + /* Receive data ready interrupt - enough data received */ + printf("[BRG] %s : %d : Transmit data ready interrupt\n", __func__, __LINE__); + + /* get the number of bytes in the FIFO */ + amount = omap3_i2c_readw(sc, OMAP35XX_I2C_BUF); + amount &= 0x3f; + amount += 1; + } + + /* sanity check we haven't overwritten the array */ + if ((sofar + amount) > len) { + printf("[BRG] %s : %d : to many bytes to write\n", __func__, __LINE__); + amount = (len - sofar); + } + + /* write the bytes from the fifo */ + for (i = 0; i < amount; i++) { + omap3_i2c_writew(sc, OMAP35XX_I2C_DATA, buf[sofar++]); + } + + /* attempt to clear the transmit ready bits */ + omap3_i2c_writew(sc, OMAP35XX_I2C_STAT, I2C_STAT_XDR | I2C_STAT_XRDY); + } + + /* reset the registers regardless if there was an error or not */ + omap3_i2c_writew(sc, OMAP35XX_I2C_IE, 0x0000); + omap3_i2c_writew(sc, OMAP35XX_I2C_CON, I2C_CON_I2C_EN | I2C_CON_MST | I2C_CON_STP); + + return(err); +} + + +/** + * omap3_i2c_transfer - called to perform the transfer + * @dev: i2c device handle + * @msgs: the messages to send/receive + * @nmsgs: the number of messages in the msgs array + * + * + * LOCKING: + * Internally locked + * + * RETURNS: + * 0 on function succeeded + * -EINVAL if invalid message is passed as an arg + */ +static int +omap3_i2c_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs) +{ + struct omap3_i2c_softc *sc = device_get_softc(dev); + int err = 0; + uint32_t i; + uint16_t len; + uint8_t *buf; + + OMAP3_I2C_LOCK(sc); + + for (i = 0; i < nmsgs; i++) { + + len = msgs[i].len; + buf = msgs[i].buf; + + /* zero byte transfers aren't allowed */ + if (len == 0 || buf == NULL) { + err = -EINVAL; + goto out; + } + + /* set the slave address */ + omap3_i2c_writew(sc, OMAP35XX_I2C_SA, msgs[i].slave); + + + /* perform the read or write */ + if (msgs[i].flags & IIC_M_RD) { + err = omap3_i2c_read_bytes(sc, buf, len); + } else { + err = omap3_i2c_write_bytes(sc, buf, len); + } + + } + +out:; + OMAP3_I2C_UNLOCK(sc); + + return(err); +} + + +/** + * omap3_i2c_callback - not sure about this one + * @dev: i2c device handle + * + * + * + * LOCKING: + * Called from timer context + * + * RETURNS: + * EH_HANDLED or EH_NOT_HANDLED + */ +static int +omap3_i2c_callback(device_t dev, int index, caddr_t data) +{ + int error = 0; + + switch (index) { + case IIC_REQUEST_BUS: + break; + + case IIC_RELEASE_BUS: + break; + + default: + error = EINVAL; + } + + return(error); +} + + + + + +static device_method_t omap3_i2c_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, omap3_i2c_probe), + DEVMETHOD(device_attach, omap3_i2c_attach), + DEVMETHOD(device_detach, omap3_i2c_detach), + + /* iicbus interface */ + DEVMETHOD(iicbus_callback, omap3_i2c_callback), + DEVMETHOD(iicbus_reset, omap3_i2c_reset), + DEVMETHOD(iicbus_transfer, omap3_i2c_transfer), + { 0, 0 } +}; + +static driver_t omap3_i2c_driver = { + "omap3_i2c", + omap3_i2c_methods, + sizeof(struct omap3_i2c_softc), +}; + +DRIVER_MODULE(omap3_i2c, omap3, omap3_i2c_driver, omap3_i2c_devclass, 0, 0); +DRIVER_MODULE(iicbus, omap3_i2c, iicbus_driver, iicbus_devclass, 0, 0); +MODULE_DEPEND(omap3_i2c, omap3_prcm, 1, 1, 1); +MODULE_DEPEND(omap3_i2c, omap3_clk, 1, 1, 1); +MODULE_DEPEND(omap3_i2c, iicbus, 1, 1, 1); Index: sys/arm/cortexa8/omap3/omap3_mem.c =================================================================== --- sys/arm/cortexa8/omap3/omap3_mem.c (revision 0) +++ sys/arm/cortexa8/omap3/omap3_mem.c (revision 0) @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2010 + * Ben Gray . + * All rights reserved. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Ben Gray. + * 4. The name of the company nor the name of the author may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY BEN GRAY ``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 BEN GRAY 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 +__FBSDID("$FreeBSD$"); + +#include +#include + +#include +#include + + +/** + * omap3_sdram_size - returns the size of the attached ram + * + * Returns the number of bytes of RAM available. + * + * LOCKING: + * none + * + * RETURNS: + * The size + */ +uint32_t +omap3_sdram_size(void) +{ + uint32_t size; + uint32_t sdrc_mcfg_0, sdrc_mcfg_1; + + sdrc_mcfg_0 = *((volatile uint32_t *)(OMAP35XX_SDRC_MCFG(0))); + sdrc_mcfg_1 = *((volatile uint32_t *)(OMAP35XX_SDRC_MCFG(1))); + + /* The size is given in bits 17:8 in 2MB chunk sizes */ + size = ((sdrc_mcfg_0 >> 8) & 0x3FF) * (2 * 1024 * 1024); + size += ((sdrc_mcfg_1 >> 8) & 0x3FF) * (2 * 1024 * 1024); + + return (size); +} + Index: sys/arm/cortexa8/omap3/omap3.c =================================================================== --- sys/arm/cortexa8/omap3/omap3.c (revision 0) +++ sys/arm/cortexa8/omap3/omap3.c (revision 0) @@ -0,0 +1,639 @@ +/* + * Copyright (c) 2010 + * Ben Gray . + * All rights reserved. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Ben Gray. + * 4. The name of the company nor the name of the author may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY BEN GRAY ``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 BEN GRAY 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include + + +struct omap3_softc { + device_t sc_dev; + bus_space_tag_t sc_iot; + + bus_space_handle_t sc_intr_ioh; /* bus space handle, i.e. address of irq regs */ + + struct rman sc_irq_rman; + struct rman sc_mem_rman; + bus_dma_tag_t sc_dmat; +}; + +struct omap3_softc *g_omap3_softc = NULL; + +static int omap3_probe(device_t); +static void omap3_identify(driver_t *, device_t); +static int omap3_attach(device_t); + + + + + +/** + * cpu_reset + * + * Called by the system to reset the CPU - obvious really + * + */ +void +cpu_reset() +{ + panic("%s: unimplemented", __func__); + + cpu_halt(); + while (1); +} + + + +/** + * omap3_install_gpio_kdb + * + * + * + */ +static void +omap3_intr_gpio_kdb(unsigned int pin, unsigned int datain, void *data) +{ +#if defined(KDB) + kdb_enter(KDB_WHY_BREAK, "KDB Button Pressed"); +#endif +} + + +/** + * omap3_install_gpio_kdb + * + * + * + */ +static void +omap3_install_gpio_kdb(void) +{ + int rc; + + if (omap3_gpio_request(7, "USER") == 0) { + + /* Set the pin as an input */ + rc = omap3_gpio_direction_input(7); + if (rc != 0) + printf("[BRG] failed to set GPIO pin as an input\n"); + + /* Enable the debounce circuit */ + rc = omap3_gpio_pin_debounce(7, 1, 500); + if (rc != 0) + printf("[BRG] failed to set GPIO debounce\n"); + + /* Install an intterupt on GPIO for triggering the KDB */ + rc = omap3_gpio_pin_intr(7, GPIO_TRIGGER_FALLING, omap3_intr_gpio_kdb, + NULL); + if (rc != 0) + printf("[BRG] failed to set GPIO interrupt trigger\n"); + + printf("[BRG] installed GPIO trigger for KDB\n"); + } +} + + +/** + * omap3_identify + * + * + * + */ +static void +omap3_identify(driver_t *driver, device_t parent) +{ + BUS_ADD_CHILD(parent, 0, "omap3", 0); +} + +/** + * omap3_probe - driver probe function + * @dev: the root device + * + * Simply sets the name of this base driver + * + */ +static int +omap3_probe(device_t dev) +{ + device_set_desc(dev, "TI OMAP3530"); + return (0); +} + +/** + * omap3_attach + * + * + * + */ +static int +omap3_attach(device_t dev) +{ + struct omap3_softc *sc; + device_t child; + + //device_printf(dev, "%b\n", omap3_read_feature_bits(), EXP_FCTRL_BITS); + + + sc = device_get_softc(dev); + sc->sc_iot = &omap3_bs_tag; + + KASSERT(g_omap3_softc == NULL, ("%s called twice?", __func__)); + g_omap3_softc = sc; + + /* Disable interrupts and config the mask and steering */ + // intr_enabled = 0; + // omap3_set_intrmask(); + // omap3_set_intrsteer(); + + /* install an interrupt post filter */ + arm_post_filter = omap3_post_filter_intr; + +/* + if (bus_space_map(sc->sc_iot, IXP425_GPIO_HWBASE, IXP425_GPIO_SIZE, + 0, &sc->sc_gpio_ioh)) + panic("%s: unable to map GPIO registers", __func__); + if (bus_space_map(sc->sc_iot, IXP425_EXP_HWBASE, IXP425_EXP_SIZE, + 0, &sc->sc_exp_ioh)) + panic("%s: unable to map Expansion Bus registers", __func__); +*/ + + /* Ensure the IRQ control registers are mapped in, we use direct pointers + * for accessing those for speed ... + */ + if (bus_space_map(sc->sc_iot, OMAP35XX_INTCPS_HWBASE, OMAP35XX_INTCPS_SIZE, + 0, &sc->sc_intr_ioh)) + panic("%s: unable to map IRQ registers", __func__); + + printf("[BRG] %s : line %d\n", __func__, __LINE__); + + + /* TODO: Investigate */ + if (bus_dma_tag_create(NULL, 1, 0, BUS_SPACE_MAXADDR_32BIT, + BUS_SPACE_MAXADDR, NULL, NULL, 0xffffffff, 0xff, 0xffffffff, 0, + NULL, NULL, &sc->sc_dmat)) + panic("%s: failed to create dma tag", __func__); + + + /* Setup the resource manager for IRQs (nb: 96 possible IRQs) */ + sc->sc_irq_rman.rm_type = RMAN_ARRAY; + sc->sc_irq_rman.rm_descr = "OMAP3 IRQs"; + if (rman_init(&sc->sc_irq_rman) != 0 || + rman_manage_region(&sc->sc_irq_rman, 0, 96) != 0) + panic("%s: failed to set up IRQ rman", __func__); + + /* Setup the memory resource manager */ + sc->sc_mem_rman.rm_type = RMAN_ARRAY; + sc->sc_mem_rman.rm_descr = "OMAP3 Memory"; + if (rman_init(&sc->sc_mem_rman) != 0 || + rman_manage_region(&sc->sc_mem_rman, 0, ~0) != 0) + panic("%s: failed to set up memory rman", __func__); + + + /* Add the PRCM driver to the list of modules */ + BUS_ADD_CHILD(dev, 0, "omap3_prcm", 0); + + /* Add the SCM driver to the list of modules */ + BUS_ADD_CHILD(dev, 0, "omap3_scm", 0); + + /* Add the tick clock to the list of modules initialised */ + BUS_ADD_CHILD(dev, 0, "omap3_clk", 0); + + /* Add the GPIO module */ + BUS_ADD_CHILD(dev, 0, "omap3_gpio", 0); + + /* Add the DMA driver to the list of modules initialised */ + BUS_ADD_CHILD(dev, 0, "omap3_dma", 0); + + /* Add the MMC/SD/SDIO driver to the list of modules */ + BUS_ADD_CHILD(dev, 0, "omap3_mmc", 0); + + /* Add the I2C controller driver to the list of modules */ + BUS_ADD_CHILD(dev, 0, "omap3_i2c", 0); + + /* Add the UART driver to the list of modules */ + child = BUS_ADD_CHILD(dev, 0, "uart", 0); + bus_set_resource(child, SYS_RES_IRQ, 0, OMAP35XX_IRQ_UART3, 1); + bus_set_resource(child, SYS_RES_IOPORT, 0, OMAP35XX_UART3_HWBASE, + OMAP35XX_UART3_SIZE); + + /* Add the USB EHCI driver to the list of modules */ + BUS_ADD_CHILD(dev, 0, "ehci", 0); + + + /* attach wired devices via hints */ + bus_enumerate_hinted_children(dev); + + bus_generic_probe(dev); + bus_generic_attach(dev); + enable_interrupts(I32_bit | F32_bit); + + /* install a GPIO interrupt handler so when the user button + * is pressed the kernel debugger is started - temporary debug + */ + omap3_install_gpio_kdb(); + + return (0); +} + + +/** + * omap3_hinted_child + * + * + * + */ +static void +omap3_hinted_child(device_t bus, const char *dname, int dunit) +{ + device_t child; + struct omap3_ivar *ivar; + + child = BUS_ADD_CHILD(bus, 0, dname, dunit); + ivar = OMAP3_IVAR(child); + resource_int_value(dname, dunit, "addr", &ivar->addr); + resource_int_value(dname, dunit, "irq", &ivar->irq); +} + +/** + * omap3_add_child + * + * + * + */ +static device_t +omap3_add_child(device_t dev, u_int order, const char *name, int unit) +{ + device_t child; + struct omap3_ivar *ivar; + + child = device_add_child_ordered(dev, order, name, unit); + if (child == NULL) + return NULL; + + ivar = malloc(sizeof(struct omap3_ivar), M_DEVBUF, M_NOWAIT); + if (ivar == NULL) { + device_delete_child(dev, child); + return NULL; + } + + ivar->addr = 0; + ivar->irq = -1; + resource_list_init(&ivar->resources); + device_set_ivars(child, ivar); + + return child; +} + +/** + * omap3_read_ivar + * + * + * + */ +static int +omap3_read_ivar(device_t bus, device_t child, int which, uintptr_t *result) +{ + struct omap3_ivar *ivar = OMAP3_IVAR(child); + + switch (which) { + case OMAP3_IVAR_ADDR: + if (ivar->addr != 0) { + *(uint32_t *)result = ivar->addr; + return 0; + } + break; + case OMAP3_IVAR_IRQ: + if (ivar->irq != -1) { + *(int *)result = ivar->irq; + return 0; + } + break; + } + return EINVAL; +} + + + +/* + * NB: This table handles P->V translations for regions setup with + * static mappings in initarm. This is used solely for calls to + * bus_alloc_resource_any; anything done with bus_space_map is + * handled elsewhere and does not require an entry here. + * + * XXX this table is also used by uart_cpu_getdev via getvbase + * (hence the public api) + */ +struct hwvtrans { + uint32_t hwbase; + uint32_t size; + uint32_t vbase; +}; + +static const struct hwvtrans * +omap3_gethwvtrans(bus_addr_t hwbase, uint32_t size) +{ + static const struct hwvtrans hwvtrans[] = { + /* The L3 mapping for some IO devices */ + { .hwbase = OMAP35XX_L3_HWBASE, + .size = OMAP35XX_L3_SIZE, + .vbase = OMAP35XX_L3_VBASE }, + /* The three main L4 mappings for IO devices */ + { .hwbase = OMAP35XX_L4_CORE_HWBASE, + .size = OMAP35XX_L4_CORE_SIZE, + .vbase = OMAP35XX_L4_CORE_VBASE }, + { .hwbase = OMAP35XX_L4_WAKEUP_HWBASE, + .size = OMAP35XX_L4_WAKEUP_SIZE, + .vbase = OMAP35XX_L4_WAKEUP_VBASE }, + { .hwbase = OMAP35XX_L4_PERIPH_HWBASE, + .size = OMAP35XX_L4_PERIPH_SIZE, + .vbase = OMAP35XX_L4_PERIPH_VBASE }, + }; + int i; + + for (i = 0; i < sizeof hwvtrans / sizeof *hwvtrans; i++) { + if (hwbase >= hwvtrans[i].hwbase && + hwbase + size <= hwvtrans[i].hwbase + hwvtrans[i].size) + return &hwvtrans[i]; + } + return NULL; +} + +/** + * omap3_getvbase + * + * For a given hardware base address returns the virtual address, ideally + * we try to ensure that virtual address match actual hardware address, it's + * much easier that way. + */ +#if 0 +static int +omap3_getvbase(uint32_t hwbase, uint32_t size, uint32_t *vbase) +{ + const struct hwvtrans *hw; + + hw = omap3_gethwvtrans(hwbase, size); + if (hw == NULL) + return (ENOENT); + *vbase = hwbase - hw->hwbase + hw->vbase; + return (0); +} +#endif + +/** + * omap3_release_resource + * + * + * + */ +static struct resource * +omap3_alloc_resource(device_t dev, device_t child, int type, int *rid, + u_long start, u_long end, u_long count, u_int flags) +{ + struct omap3_softc *sc = device_get_softc(dev); + struct resource_list_entry *rle; + struct omap3_ivar *ivar = device_get_ivars(child); + struct resource_list *rl = &ivar->resources; + struct resource *res = NULL; + + if (device_get_parent(child) != dev) + return (BUS_ALLOC_RESOURCE(device_get_parent(dev), child, + type, rid, start, end, count, flags)); + + rle = resource_list_find(rl, type, *rid); + if (rle != NULL) { + /* There is a resource list. Use it */ + if (rle->res) + panic("Resource rid %d type %d already in use", *rid, + type); + if (start == 0UL && end == ~0UL) { + start = rle->start; + count = ulmax(count, rle->count); + end = ulmax(rle->end, start + count - 1); + } + } +printf("type = %d start = %#lx end = %#lx %#lx\n", type, start, end, ~0UL); + + switch (type) { + case SYS_RES_IRQ: + res = rman_reserve_resource(&sc->sc_irq_rman, start, end, count, + flags, child); + break; + + case SYS_RES_IOPORT: + case SYS_RES_MEMORY: + res = rman_reserve_resource(&sc->sc_mem_rman, start, end, + end - start, flags, child); + if (res == NULL) + panic("Unable to map address space %#lx-%#lx", start, + end); + + rman_set_bustag(res, sc->sc_iot); + rman_set_bushandle(res, start); + + if (flags & RF_ACTIVE) { + if (bus_activate_resource(child, type, *rid, res)) { + rman_release_resource(res); + return (NULL); + } + } + break; + } + + if (res != NULL) { + rman_set_rid(res, *rid); + if (rle != NULL) { + rle->res = res; + rle->start = rman_get_start(res); + rle->end = rman_get_end(res); + rle->count = count; + } + } + + return (res); +} + + +/** + * omap3_release_resource + * + * + * + */ +static int +omap3_release_resource(device_t bus, device_t child, int type, int rid, + struct resource *r) +{ + struct omap3_ivar *ivar = device_get_ivars(child); + struct resource_list *rl = &ivar->resources; + struct resource_list_entry *rle; + int ret; + + if (rl == NULL) + return (EINVAL); + + rle = resource_list_find(rl, type, rid); + if (rle == NULL) + return (EINVAL); + + ret = rman_release_resource(r); + rle->res = NULL; + + return (ret); +} + + +/** + * omap3_activate_resource + * + * + * + */ +static int +omap3_activate_resource(device_t dev, device_t child, int type, int rid, + struct resource *r) +{ + //bus_space_handle_t p; + //int error; + + if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) { + const struct hwvtrans *vtrans; + bus_addr_t start; + + start = rman_get_bushandle(r); + vtrans = omap3_gethwvtrans(start, rman_get_size(r)); + if (vtrans == NULL) + panic("vtrans == NULL"); + rman_set_bushandle(r, vtrans->vbase + (start - vtrans->hwbase)); +printf("%x %x\n", (unsigned int)rman_get_bushandle(r), vtrans->vbase); +#if 0 + error = bus_space_map(rman_get_bustag(r), + rman_get_bushandle(r), rman_get_size(r), 0, &p); + if (error) + return (error); + rman_set_bushandle(r, p); +#endif + } + return (rman_activate_resource(r)); +} + + +/** + * omap3_deactivate_resource + * + * + * + */ +static int +omap3_deactivate_resource(device_t bus, device_t child, int type, int rid, + struct resource *r) +{ + /* NB: no private resources, just deactive */ + return (rman_deactivate_resource(r)); +} + +static struct resource_list * +omap3_get_resource_list(device_t dev, device_t child) +{ + struct omap3_ivar *ivar; + + ivar = device_get_ivars(child); + return (&(ivar->resources)); +} + + + + +static device_method_t g_omap3_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, omap3_probe), + DEVMETHOD(device_attach, omap3_attach), + DEVMETHOD(device_identify, omap3_identify), + + /* Bus interface */ + DEVMETHOD(bus_add_child, omap3_add_child), + DEVMETHOD(bus_hinted_child, omap3_hinted_child), + DEVMETHOD(bus_read_ivar, omap3_read_ivar), + + DEVMETHOD(bus_alloc_resource, omap3_alloc_resource), + DEVMETHOD(bus_release_resource, omap3_release_resource), + DEVMETHOD(bus_activate_resource, omap3_activate_resource), + DEVMETHOD(bus_deactivate_resource, omap3_deactivate_resource), + + DEVMETHOD(bus_setup_intr, omap3_setup_intr), + DEVMETHOD(bus_teardown_intr, omap3_teardown_intr), + + DEVMETHOD(bus_get_resource_list, omap3_get_resource_list), + DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource), + DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), + + {0, 0}, +}; + +static driver_t g_omap3_driver = { + "omap3", + g_omap3_methods, + sizeof(struct omap3_softc), +}; +static devclass_t g_omap3_devclass; + +DRIVER_MODULE(omap3, nexus, g_omap3_driver, g_omap3_devclass, 0, 0); + + + + + + Index: sys/arm/cortexa8/omap3/omap3_timer.c =================================================================== --- sys/arm/cortexa8/omap3/omap3_timer.c (revision 0) +++ sys/arm/cortexa8/omap3/omap3_timer.c (revision 0) @@ -0,0 +1,635 @@ +/* + * Copyright (c) 2010 + * Ben Gray . + * All rights reserved. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Ben Gray. + * 4. The name of the company nor the name of the author may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY BEN GRAY ``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 BEN GRAY 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. + */ + +/** + * To be confusing, there are two timers setup here, one is the system ticks + * that is suppose to go off 'hz' number of times a second. The other is a + * general purpose counter that is just used to provide a count to the system. + * + * For the system tick timer we use GPTIMER10, this has an acurate 1ms mode + * which is designed for system tick generation. Provided hz never gets over + * a 1000 this is perfect. + * + * For the other timer we use GPTIMER11, for no special reason other than it + * comes after 10 and they are both in the core power domain. It's set to a + * clock frequency of 12Mhz, again for no special reason except it is a nice + * round number. + * + */ +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + + +/** + * The pin to use for the heartbeat, the pin will be toggled every second. If + * you don't want a heartbeat, don't define the following. + * TODO: Move this to make options + */ +#define OMAP3_HEARTBEAT_GPIO 150 + + +/** + * The interrupt/status bits used in the timer registers. + * + */ +#define TCAR_IT_FLAG 0x04 +#define OVF_IT_FLAG 0x02 +#define MAT_IT_FLAG 0x01 + +#define TCAR_IT_ENA 0x04 +#define OVF_IT_ENA 0x02 +#define MAT_IT_ENA 0x01 + +#define TCAR_WUP_ENA 0x04 +#define OVF_WUP_ENA 0x02 +#define MAT_WUP_ENA 0x01 + + +/** + * Timer module data structure, persists forever as this driver module is + * never intented to be dynamically unloaded, see g_omap3_clk_sc. + * + */ +struct omap3_clk_softc { + device_t sc_dev; + bus_space_tag_t sc_iot; + + bus_addr_t sc_gptimer10_baseaddr; + bus_size_t sc_gptimer10_size; + bus_space_handle_t sc_gptimer10_ioh; + + bus_addr_t sc_gptimer11_baseaddr; + bus_size_t sc_gptimer11_size; + bus_space_handle_t sc_gptimer11_ioh; +}; + +static struct omap3_clk_softc *g_omap3_clk_sc = NULL; + + +/* The input oscillator freq, calculated from the boot-strap registers */ +uint32_t g_omap3_oscclk_freq = 0; + +/* The system clock (SYS_CLK) freq, calculated from the boot-strap registers */ +uint32_t g_omap3_sysclk_freq = 0; + + + +/** + * Function prototypes. + */ +int omap3_clk_intr(void *); +static unsigned omap3_timer_get_timecount(struct timecounter *tc); + + + + +static struct timecounter g_omap3_clk_timecounter = { + .tc_get_timecount = omap3_timer_get_timecount, /* get_timecount */ + .tc_poll_pps = NULL, /* no poll_pps */ + .tc_counter_mask = ~0u, /* counter_mask */ + .tc_frequency = 0, /* frequency */ + .tc_name = "OMAP3 Timer", /* name */ + .tc_quality = 1000, /* quality */ +}; + + +/** + * device_set_desc - simply sets the name of the module/device + * @dev: timer device handle + * + * + * + * RETURNS: + * 0 on success, a negative error code on failure + */ +static int +omap3_clk_probe(device_t dev) +{ + device_set_desc(dev, "TI OMAP3 Timer"); + return (0); +} + +/** + * omap3_clk_attach - module entry point + * @dev: timer device handle + * + * + * + * RETURNS: + * 0 on success, a negative error code on failure + */ +static int +omap3_clk_attach(device_t dev) +{ + struct omap3_clk_softc *sc = device_get_softc(dev); + + sc->sc_dev = dev; + sc->sc_iot = &omap3_bs_tag; + + + /* Map in the general purpose timer registers for timer 10 */ + sc->sc_gptimer10_baseaddr = OMAP35XX_GPTIMER10_HWBASE; + sc->sc_gptimer10_size = OMAP35XX_GPTIMER_SIZE; + + if (bus_space_map(sc->sc_iot, sc->sc_gptimer10_baseaddr, sc->sc_gptimer10_size, 0, &sc->sc_gptimer10_ioh)) { + panic("%s: Cannot map registers", device_get_name(dev)); + } + + + /* Map in the general purpose timer registers for timer 11 */ + sc->sc_gptimer11_baseaddr = OMAP35XX_GPTIMER11_HWBASE; + sc->sc_gptimer11_size = OMAP35XX_GPTIMER_SIZE; + + if (bus_space_map(sc->sc_iot, sc->sc_gptimer11_baseaddr, sc->sc_gptimer11_size, 0, &sc->sc_gptimer11_ioh)) { + panic("%s: Cannot map registers", device_get_name(dev)); + } + + + + /* Reserve a GPIO line for the heartbeat, also set it as an output and high */ +#if defined(OMAP3_HEARTBEAT_GPIO) + if (omap3_gpio_request(OMAP3_HEARTBEAT_GPIO, "heartbeat") == 0) { + omap3_gpio_direction_output(OMAP3_HEARTBEAT_GPIO, 1); + } +#endif + + /* Save globally, the timer module never gets unloaded */ + g_omap3_clk_sc = sc; + + return (0); +} + +static device_method_t g_omap3_clk_methods[] = { + DEVMETHOD(device_probe, omap3_clk_probe), + DEVMETHOD(device_attach, omap3_clk_attach), + {0, 0}, +}; + +static driver_t g_omap3_clk_driver = { + "omap3_clk", + g_omap3_clk_methods, + sizeof(struct omap3_clk_softc), +}; +static devclass_t g_omap3_clk_devclass; + +DRIVER_MODULE(omap3_clk, omap3, g_omap3_clk_driver, g_omap3_clk_devclass, 0, 0); + + + + + + + +/** + * omap3_timer_get_timecount - returns the count in GPTIMER11, the system counter + * @tc: pointer to the timecounter structure used to register the callback + * + * + * + * RETURNS: + * the value in the counter + */ +static unsigned +omap3_timer_get_timecount(struct timecounter *tc) +{ + struct omap3_clk_softc* sc = g_omap3_clk_sc; + uint32_t ret; + + ret = bus_space_read_4(sc->sc_iot, sc->sc_gptimer11_ioh, OMAP35XX_GPTIMER_TCRR); + + return (ret); +} + + + +/** + * omap3_get_system_clks - reads the clocking values from the boot-strap regs + * @sc: pointer to the clk module/device context + * + * Read the clocking information from the power-control/boot-strap registers, + * and stored in two global variables. + * + * RETURNS: + * nothing, values are saved in global variables + */ +static void +omap3_get_system_clks(struct omap3_clk_softc *sc) +{ + uint32_t val; + bus_space_handle_t prm_ioh; + + + /* Create a temporary mapping for the PRCM registers */ + if (bus_space_map(sc->sc_iot, OMAP35XX_PRM_HWBASE, OMAP35XX_PRM_SIZE, 0, &prm_ioh)) { + panic("%s: Cannot map registers", __func__); + } + + + /* Read the input clock freq from the configuration register */ + val = bus_space_read_4(sc->sc_iot, prm_ioh, OMAP35XX_PRM_CLKSEL); + switch (val & 0x7) { + case 0x0: + /* 12Mhz */ + g_omap3_oscclk_freq = 12000000; + break; + case 0x1: + /* 13Mhz */ + g_omap3_oscclk_freq = 13000000; + break; + case 0x2: + /* 19.2Mhz */ + g_omap3_oscclk_freq = 19200000; + break; + case 0x3: + /* 26Mhz */ + g_omap3_oscclk_freq = 26000000; + break; + case 0x4: + /* 38.4Mhz */ + g_omap3_oscclk_freq = 38400000; + break; + case 0x5: + /* 16.8Mhz */ + g_omap3_oscclk_freq = 16800000; + break; + default: + panic("%s: Invalid clock freq", __func__); + } + + + /* Read the value of the clock divider used for the system clock */ + val = bus_space_read_4(sc->sc_iot, prm_ioh, OMAP35XX_PRM_CLKSRC_CTRL); + switch (val & 0xC0) { + case 0x40: + g_omap3_sysclk_freq = g_omap3_oscclk_freq; + break; + case 0x80: + g_omap3_sysclk_freq = g_omap3_oscclk_freq / 2; + break; + default: + panic("%s: Invalid system clock divider", __func__); + } + + /* TODO: Remove debugging */ + printf("OMAP3530 Clocking frequencies, OSCCLK=%uKHz, SYSCLK=%uKHz\n", + g_omap3_oscclk_freq/1000, g_omap3_sysclk_freq/1000); + + + /* No longer need the PRM registers */ + bus_space_unmap(sc->sc_iot, prm_ioh, OMAP35XX_PRM_SIZE); +} + + +/** + * omap3_setup_timecount_timer - sets up the timecount clock (GPTIMER11) + * @sc: pointer to the clk module/device context + * + * The timer is setup to run with no prescaler off the SYSCLK, which is fixed + * by bootstrap values. It can range from 12MHz through to 38.4MHz, the + * omap3_get_system_clks() function reads the freq. + * + * RETURNS: + * nothing + */ +static void +omap3_setup_timecount_timer(struct omap3_clk_softc *sc) +{ + /* Set up system clock information */ + omap3_prcm_enable_clk(OMAP3_MODULE_GPTIMER11_FCLK); + omap3_prcm_enable_clk(OMAP3_MODULE_GPTIMER11_ICLK); + omap3_prcm_set_gptimer_clksrc(11, PRCM_USE_SYSCLK); + + + /* Set up the new clock parameters. */ + + /* reset the timer and poll on the reset complete flag */ + bus_space_write_4(sc->sc_iot, sc->sc_gptimer11_ioh, OMAP35XX_GPTIMER_TIOCP_CFG, + 0x002); + /* TODO: add a timeout */ + while ((bus_space_read_4(sc->sc_iot, sc->sc_gptimer11_ioh, OMAP35XX_GPTIMER_TISTAT) + & 0x01) == 0x00) + continue; + + + /* disable all interrupts */ + bus_space_write_4(sc->sc_iot, sc->sc_gptimer11_ioh, OMAP35XX_GPTIMER_TIER, + 0x00); + bus_space_write_4(sc->sc_iot, sc->sc_gptimer11_ioh, OMAP35XX_GPTIMER_TWER, + 0x00); + + /* set the reload to start back at zero */ + bus_space_write_4(sc->sc_iot, sc->sc_gptimer11_ioh, OMAP35XX_GPTIMER_TLDR, + 0x00000000); + + /* set the initial counter value to the reload value */ + bus_space_write_4(sc->sc_iot, sc->sc_gptimer11_ioh, OMAP35XX_GPTIMER_TCRR, + 0x00000000); + + + /* enable autoreload mode and start the timer */ + bus_space_write_4(sc->sc_iot, sc->sc_gptimer11_ioh, OMAP35XX_GPTIMER_TCLR, + 0x00000003); +} + + + +/** + * omap3_setup_timecount_timer - sets up the tick timer (GPTIMER10) + * @sc: pointer to the clk module/device context + * + * The timer is setup to run hz times a second, where hz is a kernel wide + * global variable. + * + * RETURNS: + * nothing + */ +static void +omap3_setup_tick_timer(struct omap3_clk_softc *sc) +{ + struct resource *irq; + device_t dev = sc->sc_dev; + u_int oldirqstate; + int rid = 0; + void *ihl; + + + oldirqstate = disable_interrupts(I32_bit); + + /* Register an interrupt handler for general purpose timer 10 */ + irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, OMAP35XX_IRQ_GPT10, + OMAP35XX_IRQ_GPT10, 1, RF_ACTIVE); + if (!irq) + panic("Unable to setup the clock irq handler.\n"); + else + bus_setup_intr(dev, irq, INTR_TYPE_CLK, omap3_clk_intr, NULL, + NULL, &ihl); + + + /* Set up system clock information */ + omap3_prcm_enable_clk(OMAP3_MODULE_GPTIMER10_FCLK); + omap3_prcm_enable_clk(OMAP3_MODULE_GPTIMER10_ICLK); + omap3_prcm_set_gptimer_clksrc(10, PRCM_USE_32KCLK); + + + + /* Set up the new clock parameters. */ + + /* reset the timer and poll on the reset complete flag */ + bus_space_write_4(sc->sc_iot, sc->sc_gptimer10_ioh, OMAP35XX_GPTIMER_TIOCP_CFG, + 0x002); + /* TODO: add a timeout */ + while ((bus_space_read_4(sc->sc_iot, sc->sc_gptimer10_ioh, OMAP35XX_GPTIMER_TISTAT) + & 0x01) == 0x00) + continue; + + + /* clear interrupt */ + bus_space_write_4(sc->sc_iot, sc->sc_gptimer10_ioh, OMAP35XX_GPTIMER_TISR, + TCAR_IT_FLAG | OVF_IT_FLAG | MAT_IT_FLAG); + + /* enable overflow interrupt */ + bus_space_write_4(sc->sc_iot, sc->sc_gptimer10_ioh, OMAP35XX_GPTIMER_TIER, + OVF_IT_ENA); + bus_space_write_4(sc->sc_iot, sc->sc_gptimer10_ioh, OMAP35XX_GPTIMER_TWER, + OVF_WUP_ENA); + + /* setup the timer for 1ms ticks */ + bus_space_write_4(sc->sc_iot, sc->sc_gptimer10_ioh, OMAP35XX_GPTIMER_TPIR, + 232000); + bus_space_write_4(sc->sc_iot, sc->sc_gptimer10_ioh, OMAP35XX_GPTIMER_TNIR, + -768000); + bus_space_write_4(sc->sc_iot, sc->sc_gptimer10_ioh, OMAP35XX_GPTIMER_TLDR, + 0xFFFFFFE0); + + /* setup the number of overflows before irq */ + bus_space_write_4(sc->sc_iot, sc->sc_gptimer10_ioh, OMAP35XX_GPTIMER_TOWR, + (1000 / hz)); + + /* set the initial counter value to the reload value */ + bus_space_write_4(sc->sc_iot, sc->sc_gptimer10_ioh, OMAP35XX_GPTIMER_TCRR, + 0xFFFFFFE0); + + + /* enable autoload mode and start the timer */ + bus_space_write_4(sc->sc_iot, sc->sc_gptimer10_ioh, OMAP35XX_GPTIMER_TCLR, + 0x00000003); + + restore_interrupts(oldirqstate); + + rid = 0; +} + + + +/** + * cpu_initclocks - function called by the system in init the tick clock/timer + * + * This is where both the timercount and system ticks timer are started. + * + * RETURNS: + * nothing + */ +void +cpu_initclocks(void) +{ + struct omap3_clk_softc* sc = g_omap3_clk_sc; + + /* number of microseconds between interrupts */ + tick = 1000000 / hz; + + omap3_get_system_clks(sc); + + omap3_setup_tick_timer(sc); + + omap3_setup_timecount_timer(sc); + + g_omap3_clk_timecounter.tc_frequency = g_omap3_sysclk_freq; + tc_init(&g_omap3_clk_timecounter); +} + + +/** + * DELAY - Delay for at least N microseconds. + * @n: number of microseconds to delay by + * + * This function is called all over the kernel and is suppose to provide a + * consistent delay. + * + * RETURNS: + * nothing + */ +void +DELAY(int n) +{ + struct omap3_clk_softc* sc = g_omap3_clk_sc; + int32_t counts_per_usec; + int32_t counts; + uint32_t first, last; + + + if (n == 0) + return; + + /* Check the timers are setup, if not just use a for loop for the meantime */ + if (g_omap3_clk_timecounter.tc_frequency == 0) { + + /* TODO: Added a more acurate loop */ + while (n--) + continue; + + return; + } + + /* Get the number of times to count */ + counts_per_usec = ((g_omap3_clk_timecounter.tc_frequency / 1000000) + 1); + + /* + * Clamp the timeout at a maximum value (about 32 seconds with + * a 66MHz clock). *Nobody* should be delay()ing for anywhere + * near that length of time and if they are, they should be hung + * out to dry. + */ + if (n >= (0x80000000U / counts_per_usec)) + counts = (0x80000000U / counts_per_usec) - 1; + else + counts = n * counts_per_usec; + + + first = bus_space_read_4(sc->sc_iot, sc->sc_gptimer11_ioh, OMAP35XX_GPTIMER_TCRR); + + while (counts > 0) { + last = bus_space_read_4(sc->sc_iot, sc->sc_gptimer11_ioh, OMAP35XX_GPTIMER_TCRR); + counts -= (int32_t)(last - first); + first = last; + } +} + +/** + * omap3_clk_intr - interrupt handler for the tick timer (GPTIMER10) + * @arg: the trapframe, needed for the hardclock system function. + * + * This interrupt is triggered every hz times a second. It's role is basically + * to just clear the interrupt status and set it up for triggering again, plus + * tell the system a tick timer has gone off by calling the hardclock() + * function from the kernel API. + * + * RETURNS: + * Always returns FILTER_HANDLED. + */ +int +omap3_clk_intr(void *arg) +{ + struct omap3_clk_softc* sc = g_omap3_clk_sc; + struct trapframe *frame = arg; + uint32_t val; +#if defined(OMAP3_HEARTBEAT_GPIO) + static int heartbeat_cnt = 0; +#endif + + /* read the interrupt status flag */ + val = bus_space_read_4(sc->sc_iot, sc->sc_gptimer10_ioh, + OMAP35XX_GPTIMER_TISR); + + /* clear the interrupt flag */ + bus_space_write_4(sc->sc_iot, sc->sc_gptimer10_ioh, OMAP35XX_GPTIMER_TISR, + val); + + /* check if an actual overflow interrupt */ + if (!(val & OVF_IT_FLAG)) + return (FILTER_HANDLED); + + /* heartbeat */ +#if defined(OMAP3_HEARTBEAT_GPIO) + if (heartbeat_cnt++ >= (hz/2)) { + // printf("[BRG] ** tick **\n"); + omap3_gpio_pin_toggle(OMAP3_HEARTBEAT_GPIO); + heartbeat_cnt = 0; + } +#endif + + /* tell the system a timer tick has gone off */ + hardclock(TRAPF_USERMODE(frame), TRAPF_PC(frame)); + + /* indicate we've handed the interrupt */ + return (FILTER_HANDLED); +} + + +/** + * cpu_startprofclock - Starts the profile clock + * + * + * RETURNS: + * nothing + */ +void +cpu_startprofclock(void) +{ + /* TODO: implement */ +} + + +/** + * cpu_startprofclock - Stop the profile clock + * + * + * RETURNS: + * nothing + */ +void +cpu_stopprofclock(void) +{ + /* TODO: implement */ +} Index: sys/arm/cortexa8/omap3/omap3_mmc.h =================================================================== --- sys/arm/cortexa8/omap3/omap3_mmc.h (revision 0) +++ sys/arm/cortexa8/omap3/omap3_mmc.h (revision 0) @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2010 + * Ben Gray . + * All rights reserved. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Ben Gray. + * 4. The name of the company nor the name of the author may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY BEN GRAY ``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 BEN GRAY 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 _OMAP3_MMC_H_ +#define _OMAP3_MMC_H_ + +/** + * Header file for the OMAP3530 MMC/SD/SDIO driver. + * + * Simply contains register bit flags. + */ + +#define OMAP3_MMC_REF_CLK 96000000 /* 96Mhz */ + +#define MMCHS_STAT_BADA (1UL << 29) +#define MMCHS_STAT_CERR (1UL << 28) +#define MMCHS_STAT_ACE (1UL << 24) +#define MMCHS_STAT_DEB (1UL << 22) +#define MMCHS_STAT_DCRC (1UL << 21) +#define MMCHS_STAT_DTO (1UL << 20) +#define MMCHS_STAT_CIE (1UL << 19) +#define MMCHS_STAT_CEB (1UL << 18) +#define MMCHS_STAT_CCRC (1UL << 17) +#define MMCHS_STAT_CTO (1UL << 16) +#define MMCHS_STAT_ERRI (1UL << 15) +#define MMCHS_STAT_OBI (1UL << 9) +#define MMCHS_STAT_CIRQ (1UL << 8) +#define MMCHS_STAT_BRR (1UL << 5) +#define MMCHS_STAT_BWR (1UL << 4) +#define MMCHS_STAT_BGE (1UL << 2) +#define MMCHS_STAT_TC (1UL << 1) +#define MMCHS_STAT_CC (1UL << 0) + +#define MMCHS_STAT_CLEAR_MASK 0x3BFF8337UL + + +#define MMCHS_SYSCTL_SRD (1UL << 26) +#define MMCHS_SYSCTL_SRC (1UL << 25) +#define MMCHS_SYSCTL_SRA (1UL << 24) +#define MMCHS_SYSCTL_DTO(x) (((x) & 0xf) << 16) +#define MMCHS_SYSCTL_DTO_MASK MMCHS_SYSCTL_DTO(0xf) +#define MMCHS_SYSCTL_CLKD(x) (((x) & 0x3ff) << 6) +#define MMCHS_SYSCTL_CLKD_MASK MMCHS_SYSCTL_CLKD(0x3ff) +#define MMCHS_SYSCTL_CEN (1UL << 2) +#define MMCHS_SYSCTL_ICS (1UL << 1) +#define MMCHS_SYSCTL_ICE (1UL << 0) + +#define MMCHS_HCTL_OBWE (1UL << 27) +#define MMCHS_HCTL_REM (1UL << 26) +#define MMCHS_HCTL_INS (1UL << 25) +#define MMCHS_HCTL_IWE (1UL << 24) +#define MMCHS_HCTL_IBG (1UL << 19) +#define MMCHS_HCTL_RWC (1UL << 18) +#define MMCHS_HCTL_CR (1UL << 17) +#define MMCHS_HCTL_SBGR (1UL << 16) +#define MMCHS_HCTL_SDVS_MASK MMCHS_HCTL_SDVS(0x3) +#define MMCHS_HCTL_SDVS(x) (((x) & 0x3) << 9) +#define MMCHS_HCTL_SDBP (1UL << 8) +#define MMCHS_HCTL_DTW (1UL << 1) + +#define MMCHS_CAPA_VS18 (1UL << 26) +#define MMCHS_CAPA_VS30 (1UL << 25) +#define MMCHS_CAPA_VS33 (1UL << 24) + + + +#define MMCHS_CMD_CMD_TYPE_IO_ABORT (3UL << 21) +#define MMCHS_CMD_CMD_TYPE_FUNC_SEL (2UL << 21) +#define MMCHS_CMD_CMD_TYPE_SUSPEND (1UL << 21) +#define MMCHS_CMD_CMD_TYPE_OTHERS (0UL << 21) +#define MMCHS_CMD_CMD_TYPE_MASK (3UL << 22) + +#define MMCHS_CMD_DP (1UL << 21) +#define MMCHS_CMD_CICE (1UL << 20) +#define MMCHS_CMD_CCCE (1UL << 19) + +#define MMCHS_CMD_RSP_TYPE_MASK (3UL << 16) +#define MMCHS_CMD_RSP_TYPE_NO (0UL << 16) +#define MMCHS_CMD_RSP_TYPE_136 (1UL << 16) +#define MMCHS_CMD_RSP_TYPE_48 (2UL << 16) +#define MMCHS_CMD_RSP_TYPE_48_BSY (3UL << 16) + +#define MMCHS_CMD_MSBS (1UL << 5) +#define MMCHS_CMD_DDIR (1UL << 4) +#define MMCHS_CMD_ACEN (1UL << 2) +#define MMCHS_CMD_BCE (1UL << 1) +#define MMCHS_CMD_DE (1UL << 0) + + + +#define MMCHS_CON_CLKEXTFREE (1UL << 16) +#define MMCHS_CON_PADEN (1UL << 15) +#define MMCHS_CON_OBIE (1UL << 14) +#define MMCHS_CON_OBIP (1UL << 13) +#define MMCHS_CON_CEATA (1UL << 12) +#define MMCHS_CON_CTPL (1UL << 11) + +#define MMCHS_CON_DVAL_8_4MS (3UL << 9) +#define MMCHS_CON_DVAL_1MS (2UL << 9) +#define MMCHS_CON_DVAL_231US (1UL << 9) +#define MMCHS_CON_DVAL_33US (0UL << 9) +#define MMCHS_CON_DVAL_MASK (3UL << 9) + +#define MMCHS_CON_WPP (1UL << 8) +#define MMCHS_CON_CDP (1UL << 7) +#define MMCHS_CON_MIT (1UL << 6) +#define MMCHS_CON_DW8 (1UL << 5) +#define MMCHS_CON_MODE (1UL << 4) +#define MMCHS_CON_STR (1UL << 3) +#define MMCHS_CON_HR (1UL << 2) +#define MMCHS_CON_INIT (1UL << 1) +#define MMCHS_CON_OD (1UL << 0) + + + + +#endif /* _OMAP3_MMC_H_ */ Index: sys/arm/cortexa8/omap3/uart_cpu_omap3.c =================================================================== --- sys/arm/cortexa8/omap3/uart_cpu_omap3.c (revision 0) +++ sys/arm/cortexa8/omap3/uart_cpu_omap3.c (revision 0) @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2010 + * Ben Gray . + * All rights reserved. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Ben Gray. + * 4. The name of the company nor the name of the author may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY BEN GRAY ``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 BEN GRAY 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +bus_space_tag_t uart_bus_space_io; +bus_space_tag_t uart_bus_space_mem; + + +/* --------------------------------------------------------------- */ +/* uart_cpu_eqres + * + * Checks if the two UART base addresses are equal, if they are + * 1 is returned, otherwise 0 is returned. + */ +int uart_cpu_eqres(struct uart_bas *b1, struct uart_bas *b2) +{ + return ((b1->bsh == b2->bsh && b1->bst == b2->bst) ? 1 : 0); +} + +/* --------------------------------------------------------------- */ +/* uart_cpu_getdev + * + * + * + */ +int uart_cpu_getdev(int devtype, struct uart_devinfo *di) +{ + di->ops = uart_getops(&uart_ns8250_class); + di->bas.chan = 0; + di->bas.bst = &omap3_bs_tag; + di->bas.regshft = 2; + di->bas.rclk = OMAP35XX_UART_FREQ; + di->bas.bsh = OMAP35XX_UART3_VBASE; + di->baudrate = 115200; + di->databits = 8; + di->stopbits = 1; + di->parity = UART_PARITY_NONE; + uart_bus_space_mem = NULL; + uart_bus_space_io = &omap3_bs_tag; + + return (0); +} Index: sys/arm/cortexa8/omap3/omap3_scm.c =================================================================== --- sys/arm/cortexa8/omap3/omap3_scm.c (revision 0) +++ sys/arm/cortexa8/omap3/omap3_scm.c (revision 0) @@ -0,0 +1,547 @@ +/* + * Copyright (c) 2010 + * Ben Gray . + * All rights reserved. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Ben Gray. + * 4. The name of the company nor the name of the author may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY BEN GRAY ``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 BEN GRAY 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. + */ + +/** + * SCM - System Control Module + * + * Hopefully in the end this module will contain a bunch of utility functions + * for configuring and querying the general system control registers, but for + * now it only does pin(pad) multiplexing. + * + * This is different from the GPIO module in that it is used to configure the + * pins between modules not just GPIO input output. + * + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + + + +/** + * The following array maps GPIO numbers to their corresponding PADCONF + * registers. + */ +static uint16_t omap3_scm_gpio_map[192] = { + [0] = CONTROL_PADCONF_SYS_NIRQ, + [1] = CONTROL_PADCONF_SYS_CLKREQ, + [2] = CONTROL_PADCONF_SYS_BOOT0, + [3] = CONTROL_PADCONF_SYS_BOOT1, + [4] = CONTROL_PADCONF_SYS_BOOT2, + [5] = CONTROL_PADCONF_SYS_BOOT3, + [6] = CONTROL_PADCONF_SYS_BOOT3, + [7] = CONTROL_PADCONF_SYS_BOOT5, + [8] = CONTROL_PADCONF_SYS_BOOT6, + [9] = CONTROL_PADCONF_SYS_OFF_MODE, + [10] = CONTROL_PADCONF_SYS_CLKOUT1, + [11] = CONTROL_PADCONF_JTAG_EMU0, + [12] = CONTROL_PADCONF_ETK_CLK, + [13] = CONTROL_PADCONF_ETK_CTL, + [14] = CONTROL_PADCONF_ETK_D0, + [15] = CONTROL_PADCONF_ETK_D1, + [16] = CONTROL_PADCONF_ETK_D2, + [17] = CONTROL_PADCONF_ETK_D3, + [18] = CONTROL_PADCONF_ETK_D4, + [19] = CONTROL_PADCONF_ETK_D5, + [20] = CONTROL_PADCONF_ETK_D6, + [21] = CONTROL_PADCONF_ETK_D7, + [22] = CONTROL_PADCONF_ETK_D8, + [23] = CONTROL_PADCONF_ETK_D9, + [24] = CONTROL_PADCONF_ETK_D10, + [25] = CONTROL_PADCONF_ETK_D11, + [26] = CONTROL_PADCONF_ETK_D12, + [27] = CONTROL_PADCONF_ETK_D13, + [28] = CONTROL_PADCONF_ETK_D14, + [29] = CONTROL_PADCONF_ETK_D15, + [30] = CONTROL_PADCONF_SYS_NRESWARM, + [31] = CONTROL_PADCONF_JTAG_EMU1, + [32] = CONTROL_PADCONF_SAD2D_FRINT, + [33] = 0, /* no padconf for gpio_33 */ + [34] = CONTROL_PADCONF_GPMC_A1, + [35] = CONTROL_PADCONF_GPMC_A2, + [36] = CONTROL_PADCONF_GPMC_A3, + [37] = CONTROL_PADCONF_GPMC_A4, + [38] = CONTROL_PADCONF_GPMC_A5, + [39] = CONTROL_PADCONF_GPMC_A6, + [40] = CONTROL_PADCONF_GPMC_A7, + [41] = CONTROL_PADCONF_GPMC_A8, + [42] = CONTROL_PADCONF_GPMC_A9, + [43] = CONTROL_PADCONF_GPMC_A10, + [44] = CONTROL_PADCONF_GPMC_D8, + [45] = CONTROL_PADCONF_GPMC_D9, + [46] = CONTROL_PADCONF_GPMC_D10, + [47] = CONTROL_PADCONF_GPMC_D11, + [48] = CONTROL_PADCONF_GPMC_D12, + [49] = CONTROL_PADCONF_GPMC_D13, + [50] = CONTROL_PADCONF_GPMC_D14, + [51] = CONTROL_PADCONF_GPMC_D15, + [52] = CONTROL_PADCONF_GPMC_NCS1, + [53] = CONTROL_PADCONF_GPMC_NCS2, + [54] = CONTROL_PADCONF_GPMC_NCS3, + [55] = CONTROL_PADCONF_GPMC_NCS4, + [56] = CONTROL_PADCONF_GPMC_NCS5, + [57] = CONTROL_PADCONF_GPMC_NCS6, + [58] = CONTROL_PADCONF_GPMC_NCS7, + [59] = CONTROL_PADCONF_GPMC_CLK, + [60] = CONTROL_PADCONF_GPMC_NBE0_CLE, + [61] = CONTROL_PADCONF_GPMC_NBE1, + [62] = CONTROL_PADCONF_GPMC_NWP, + [63] = CONTROL_PADCONF_GPMC_WAIT1, + [64] = CONTROL_PADCONF_GPMC_WAIT2, + [65] = CONTROL_PADCONF_GPMC_WAIT3, + [66] = CONTROL_PADCONF_DSS_PCLK, + [67] = CONTROL_PADCONF_DSS_HSYNC, + [68] = CONTROL_PADCONF_DSS_VSYNC, + [69] = CONTROL_PADCONF_DSS_ACBIAS, + [70] = CONTROL_PADCONF_DSS_DATA0, + [71] = CONTROL_PADCONF_DSS_DATA1, + [72] = CONTROL_PADCONF_DSS_DATA2, + [73] = CONTROL_PADCONF_DSS_DATA3, + [74] = CONTROL_PADCONF_DSS_DATA4, + [75] = CONTROL_PADCONF_DSS_DATA5, + [76] = CONTROL_PADCONF_DSS_DATA6, + [77] = CONTROL_PADCONF_DSS_DATA7, + [78] = CONTROL_PADCONF_DSS_DATA8, + [79] = CONTROL_PADCONF_DSS_DATA9, + [80] = CONTROL_PADCONF_DSS_DATA10, + [81] = CONTROL_PADCONF_DSS_DATA11, + [82] = CONTROL_PADCONF_DSS_DATA12, + [83] = CONTROL_PADCONF_DSS_DATA13, + [84] = CONTROL_PADCONF_DSS_DATA14, + [85] = CONTROL_PADCONF_DSS_DATA15, + [86] = CONTROL_PADCONF_DSS_DATA16, + [87] = CONTROL_PADCONF_DSS_DATA17, + [88] = CONTROL_PADCONF_DSS_DATA18, + [89] = CONTROL_PADCONF_DSS_DATA19, + [90] = CONTROL_PADCONF_DSS_DATA20, + [91] = CONTROL_PADCONF_DSS_DATA21, + [92] = CONTROL_PADCONF_DSS_DATA22, + [93] = CONTROL_PADCONF_DSS_DATA23, + [94] = CONTROL_PADCONF_CAM_HS, + [95] = CONTROL_PADCONF_CAM_VS, + [96] = CONTROL_PADCONF_CAM_XCLKA, + [97] = CONTROL_PADCONF_CAM_PCLK, + [98] = CONTROL_PADCONF_CAM_FLD, + [99] = CONTROL_PADCONF_CAM_D0, + [100] = CONTROL_PADCONF_CAM_D1, + [101] = CONTROL_PADCONF_CAM_D2, + [102] = CONTROL_PADCONF_CAM_D3, + [103] = CONTROL_PADCONF_CAM_D4, + [104] = CONTROL_PADCONF_CAM_D5, + [105] = CONTROL_PADCONF_CAM_D6, + [106] = CONTROL_PADCONF_CAM_D7, + [107] = CONTROL_PADCONF_CAM_D8, + [108] = CONTROL_PADCONF_CAM_D9, + [109] = CONTROL_PADCONF_CAM_D10, + [110] = CONTROL_PADCONF_CAM_D11, + [111] = CONTROL_PADCONF_CAM_XCLKB, + [112] = CONTROL_PADCONF_CSI2_DX0, + [113] = CONTROL_PADCONF_CSI2_DY0, + [114] = CONTROL_PADCONF_CSI2_DX1, + [115] = CONTROL_PADCONF_CSI2_DY1, + [116] = CONTROL_PADCONF_MCBSP2_FSX, + [117] = CONTROL_PADCONF_MCBSP2_CLKX, + [118] = CONTROL_PADCONF_MCBSP2_DR, + [119] = CONTROL_PADCONF_MCBSP2_DX, + [120] = CONTROL_PADCONF_MMC1_CLK, + [121] = CONTROL_PADCONF_MMC1_CMD, + [122] = CONTROL_PADCONF_MMC1_DAT0, + [123] = CONTROL_PADCONF_MMC1_DAT1, + [124] = CONTROL_PADCONF_MMC1_DAT2, + [125] = CONTROL_PADCONF_MMC1_DAT3, + [126] = CONTROL_PADCONF_MMC1_DAT4, /* also CONTROL_PADCONF_CAM_STROBE */ + [127] = CONTROL_PADCONF_MMC1_DAT5, + [128] = CONTROL_PADCONF_MMC1_DAT6, + [129] = CONTROL_PADCONF_MMC1_DAT7, + [130] = CONTROL_PADCONF_MMC2_CLK, + [131] = CONTROL_PADCONF_MMC2_CMD, + [132] = CONTROL_PADCONF_MMC2_DAT0, + [133] = CONTROL_PADCONF_MMC2_DAT1, + [134] = CONTROL_PADCONF_MMC2_DAT2, + [135] = CONTROL_PADCONF_MMC2_DAT3, + [136] = CONTROL_PADCONF_MMC2_DAT4, + [137] = CONTROL_PADCONF_MMC2_DAT5, + [138] = CONTROL_PADCONF_MMC2_DAT6, + [139] = CONTROL_PADCONF_MMC2_DAT7, + [140] = CONTROL_PADCONF_MCBSP3_DX, + [141] = CONTROL_PADCONF_MCBSP3_DR, + [142] = CONTROL_PADCONF_MCBSP3_CLKX, + [143] = CONTROL_PADCONF_MCBSP3_FSX, + [144] = CONTROL_PADCONF_UART2_CTS, + [145] = CONTROL_PADCONF_UART2_RTS, + [146] = CONTROL_PADCONF_UART2_TX, + [147] = CONTROL_PADCONF_UART2_RX, + [148] = CONTROL_PADCONF_UART1_TX, + [149] = CONTROL_PADCONF_UART1_RTS, + [150] = CONTROL_PADCONF_UART1_CTS, + [151] = CONTROL_PADCONF_UART1_RX, + [152] = CONTROL_PADCONF_MCBSP4_CLKX, + [153] = CONTROL_PADCONF_MCBSP4_DR, + [154] = CONTROL_PADCONF_MCBSP4_DX, + [155] = CONTROL_PADCONF_MCBSP4_FSX, + [156] = CONTROL_PADCONF_MCBSP1_CLKR, + [157] = CONTROL_PADCONF_MCBSP1_FSR, + [158] = CONTROL_PADCONF_MCBSP1_DX, + [159] = CONTROL_PADCONF_MCBSP1_DR, + [160] = CONTROL_PADCONF_MCBSP_CLKS, + [161] = CONTROL_PADCONF_MCBSP1_FSX, + [162] = CONTROL_PADCONF_MCBSP1_CLKX, + [163] = CONTROL_PADCONF_UART3_CTS_RCTX, + [164] = CONTROL_PADCONF_UART3_RTS_SD, + [165] = CONTROL_PADCONF_UART3_RX_IRRX, + [166] = CONTROL_PADCONF_UART3_TX_IRTX, + [167] = CONTROL_PADCONF_CAM_WEN, + [168] = CONTROL_PADCONF_I2C2_SCL, + [169] = CONTROL_PADCONF_HSUSB0_DATA3, + [170] = CONTROL_PADCONF_HDQ_SIO, + [171] = CONTROL_PADCONF_MCSPI1_CLK, + [172] = CONTROL_PADCONF_MCSPI1_SIMO, + [173] = CONTROL_PADCONF_MCSPI1_SOMI, + [174] = CONTROL_PADCONF_MCSPI1_CS0, + [175] = CONTROL_PADCONF_MCSPI1_CS1, + [176] = CONTROL_PADCONF_MCSPI1_CS2, + [177] = CONTROL_PADCONF_MCSPI1_CS3, + [178] = CONTROL_PADCONF_MCSPI2_CLK, + [179] = CONTROL_PADCONF_MCSPI2_SIMO, + [180] = CONTROL_PADCONF_MCSPI2_SOMI, + [181] = CONTROL_PADCONF_MCSPI2_CS0, + [182] = CONTROL_PADCONF_MCSPI2_CS1, + [183] = CONTROL_PADCONF_I2C2_SDA, + [184] = CONTROL_PADCONF_I2C3_SCL, + [185] = CONTROL_PADCONF_I2C3_SDA, + [186] = CONTROL_PADCONF_SYS_CLKOUT2, + [187] = CONTROL_PADCONF_SAD2D_SPINT, + [188] = CONTROL_PADCONF_HSUSB0_DATA4, + [189] = CONTROL_PADCONF_HSUSB0_DATA5, + [190] = CONTROL_PADCONF_HSUSB0_DATA6, + [191] = CONTROL_PADCONF_HSUSB0_DATA7, +}; + + + +/** + * + */ +struct omap3_scm_softc { + device_t sc_dev; + + bus_space_tag_t sc_iotag; + bus_space_handle_t sc_ioh; + +}; + +static struct omap3_scm_softc *g_omap3_scm_sc = NULL; + + + +/** + * omap3_scm_reads - reads a 16-bit value from one of the PADCONFS registers + * @sc: PinMux device context + * @off: The offset of a register from the SCM register address range + * + * + * RETURNS: + * 16-bit value read from the register. + */ +static inline uint16_t +omap3_scm_reads(struct omap3_scm_softc *sc, bus_size_t off) +{ + return bus_space_read_2(sc->sc_iotag, sc->sc_ioh, off); +} + +/** + * omap3_scm_writes - writes a 16-bit value to one of the PADCONFS registers + * @sc: PinMux device context + * @off: The offset of a register from the SCM register address range + * + * + * RETURNS: + * nothing + */ +static inline void +omap3_scm_writes(struct omap3_scm_softc *sc, bus_size_t off, uint16_t val) +{ + bus_space_write_2(sc->sc_iotag, sc->sc_ioh, off, val); +} + + +/** + * omap3_scm_readl - reads a 32-bit value from one of the PADCONFS registers + * @sc: SCM device context + * @off: The offset of a register from the SCM register address range + * + * + * RETURNS: + * 32-bit value read from the register. + */ +static inline uint32_t +omap3_scm_readl(struct omap3_scm_softc *sc, bus_size_t off) +{ + return bus_space_read_4(sc->sc_iotag, sc->sc_ioh, off); +} + +/** + * omap3_scm_writel - writes a 32-bit value to one of the PADCONFS registers + * @sc: SCM device context + * @off: The offset of a register from the SCM register address range + * + * + * RETURNS: + * nothing + */ +static inline void +omap3_scm_writel(struct omap3_scm_softc *sc, bus_size_t off, uint32_t val) +{ + bus_space_write_4(sc->sc_iotag, sc->sc_ioh, off, val); +} + + + + + + +/** + * omap3_scm_probe - driver probe function + * @dev: pinumx device handle + * + * Simply sets the name of the driver + * + * + * RETURNS: + * Returns 0 on sucess, a negative error code on failure. + */ +static int +omap3_scm_probe(device_t dev) +{ + + device_set_desc(dev, "TI OMAP3 System Control Module"); + return (0); +} + + + + +/** + * omap3_scm_attach - driver attach function + * @dev: scm device handle + * + * Sets up the driver data structure and initialises all the fields. + * + * RETURNS: + * Returns 0 on sucess, a negative error code on failure. + */ +static int +omap3_scm_attach(device_t dev) +{ + struct omap3_scm_softc *sc = device_get_softc(dev); + + /* Setup the basics */ + sc->sc_dev = dev; + sc->sc_iotag = &omap3_bs_tag; + + + /* Map in the SCM register set, contains the PADCONF registers */ + if (bus_space_map(sc->sc_iotag, OMAP35XX_SCM_HWBASE, OMAP35XX_SCM_SIZE, + 0, &sc->sc_ioh)) { + panic("%s: Cannot map registers", device_get_name(dev)); + } + + /* Store the scm structure globally, this driver should never be unloaded */ + g_omap3_scm_sc = sc; + + return (0); +} + + +static device_method_t g_omap3_scm_methods[] = { + DEVMETHOD(device_probe, omap3_scm_probe), + DEVMETHOD(device_attach, omap3_scm_attach), + { 0, 0 } +}; + +static driver_t g_omap3_scm_driver = { + "omap3_scm", + g_omap3_scm_methods, + sizeof(struct omap3_scm_softc), +}; + +static devclass_t g_omap3_scm_devclass; + +DRIVER_MODULE(omap3_scm, omap3, g_omap3_scm_driver, g_omap3_scm_devclass, 0, 0); + + + + + + +/** + * omap3_scm_padconf_set - requests 'exclusive' access to the GPIO pin. + * @pin: the pin number (0-195) + * @name: the name to give the pin (currently not used). + * + * + * + * LOCKING: + * Internally locks it's own context. + * + * RETURNS: + * 0 on success. + * -ENOMEM on driver not initialised. + * -EINVAL if pin requested is outside valid range or already in use. + */ +int +omap3_scm_padconf_set(uint32_t padconf, unsigned int mode, unsigned int state) +{ + struct omap3_scm_softc *sc = g_omap3_scm_sc; + uint16_t val; + + /* sanity checking */ + if (sc == NULL) + return(-ENOMEM); + + /* populate the new value for the PADCONF register */ + val = (uint16_t)(state & 0xFF18) | (uint16_t)(mode & 0x7); + + /* write the register value (16-bit writes) */ + omap3_scm_writes(sc, padconf, val); + + printf("[BRG] %s : %d : val = 0x%04x : 0x%04x[0x%04x] => 0x%08x\n", __func__, __LINE__, + val, padconf, (padconf & ~0x3), omap3_scm_readl(sc, (padconf & ~0x3))); + + return 0; +} + +/** + * omap3_scm_padconf_set_gpiomode - converts a pad to GPIO mode. + * @pin: the pin number (0-191) + * @state: the input/output, pull-up/pull-down state, can be one + * of the following values: + * - PADCONF_PIN_OUTPUT + * - PADCONF_PIN_INPUT + * - PADCONF_PIN_INPUT_PULLUP + * - PADCONF_PIN_INPUT_PULLDOWN + * + * LOCKING: + * Internally locks it's own context. + * + * RETURNS: + * 0 on success. + * -ENOMEM on driver not initialised. + * -EINVAL if pin requested is outside valid range or already in use. + */ +int +omap3_scm_padconf_set_gpiomode(uint32_t pin, unsigned int state) +{ + struct omap3_scm_softc *sc = g_omap3_scm_sc; + uint16_t val; + uint16_t mode; + uint32_t padconf; + uint32_t max_gpio = sizeof(omap3_scm_gpio_map) / sizeof(omap3_scm_gpio_map[0]); + + /* sanity checking */ + if (sc == NULL) + return(-ENOMEM); + if (pin >= max_gpio) + return(-EINVAL); + + /* get the corresponding PADCONF register for the GPIO */ + padconf = omap3_scm_gpio_map[pin]; + if (padconf != 0) { + + /* mode is always 4 for GPIO pins */ + mode = 4; + + /* populate the new value for the PADCONF register */ + val = (uint16_t)(state & 0xFF18) | (uint16_t)(mode & 0x7); + + /* write the register value (16-bit writes) */ + omap3_scm_writes(sc, padconf, val); + + printf("[BRG] %s : %d : val = 0x%04x : 0x%04x[0x%04x] => 0x%08x\n", __func__, __LINE__, + val, padconf, (padconf & ~0x3), omap3_scm_readl(sc, (padconf & ~0x3))); + } + + return 0; +} + + +/** + * omap3_scm_padconf_get - requests 'exclusive' access to the GPIO pin. + * @pin: the pin number (0-195) + * @name: the name to give the pin (currently not used). + * + * + * + * LOCKING: + * Internally locks it's own context. + * + * RETURNS: + * 0 on success. + * -ENOMEM on driver not initialised. + * -EINVAL if pin requested is outside valid range or already in use. + */ +int +omap3_scm_padconf_get(uint32_t padconf, unsigned int *mode, unsigned int *state) +{ + struct omap3_scm_softc *sc = g_omap3_scm_sc; + uint16_t val; + + /* sanity checking */ + if (sc == NULL) + return(-ENOMEM); + + val = omap3_scm_reads(sc, padconf); + + if (mode != NULL) + *mode = (val & 0x7); + if (state != NULL) + *state = (val & 0xFF18); + + return 0; +} + + + Index: sys/arm/cortexa8/omap3/omap3_i2c.h =================================================================== --- sys/arm/cortexa8/omap3/omap3_i2c.h (revision 0) +++ sys/arm/cortexa8/omap3/omap3_i2c.h (revision 0) @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2010 + * Ben Gray . + * All rights reserved. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Ben Gray. + * 4. The name of the company nor the name of the author may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY BEN GRAY ``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 BEN GRAY 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 _OMAP3_I2C_H_ +#define _OMAP3_I2C_H_ + +/** + * Header file for the OMAP3530 I2C driver. + * + * Simply contains register bit flags. + */ + +#define I2C_CON_I2C_EN (1UL << 15) + +#define I2C_CON_OPMODE_STD (0UL << 12) +#define I2C_CON_OPMODE_HS (1UL << 12) +#define I2C_CON_OPMODE_SCCB (2UL << 12) +#define I2C_CON_OPMODE_MASK (3UL << 13) + +#define I2C_CON_I2C_STB (1UL << 11) +#define I2C_CON_MST (1UL << 10) +#define I2C_CON_TRX (1UL << 9) +#define I2C_CON_XSA (1UL << 8) +#define I2C_CON_XOA0 (1UL << 7) +#define I2C_CON_XOA1 (1UL << 6) +#define I2C_CON_XOA2 (1UL << 5) +#define I2C_CON_XOA3 (1UL << 4) +#define I2C_CON_STP (1UL << 1) +#define I2C_CON_STT (1UL << 0) + + +#define I2C_IE_XDR (1UL << 14) /* Transmit draining interrupt */ +#define I2C_IE_RDR (1UL << 13) /* Receive draining interrupt */ +#define I2C_IE_AAS (1UL << 9) /* Addressed as Slave interrupt */ +#define I2C_IE_BF (1UL << 8) /* Bus Free interrupt */ +#define I2C_IE_AERR (1UL << 7) /* Access Error interrupt */ +#define I2C_IE_STC (1UL << 6) /* Start Condition interrupt */ +#define I2C_IE_GC (1UL << 5) /* General Call interrupt */ +#define I2C_IE_XRDY (1UL << 4) /* Transmit Data Ready interrupt */ +#define I2C_IE_RRDY (1UL << 3) /* Receive Data Ready interrupt */ +#define I2C_IE_ARDY (1UL << 2) /* Register Access Ready interrupt */ +#define I2C_IE_NACK (1UL << 1) /* No Acknowledgment interrupt */ +#define I2C_IE_AL (1UL << 0) /* Arbitration Lost interrupt */ + + +#define I2C_STAT_XDR (1UL << 14) +#define I2C_STAT_RDR (1UL << 13) +#define I2C_STAT_BB (1UL << 12) +#define I2C_STAT_ROVR (1UL << 11) +#define I2C_STAT_XUDF (1UL << 10) +#define I2C_STAT_AAS (1UL << 9) +#define I2C_STAT_BF (1UL << 8) +#define I2C_STAT_AERR (1UL << 7) +#define I2C_STAT_STC (1UL << 6) +#define I2C_STAT_GC (1UL << 5) +#define I2C_STAT_XRDY (1UL << 4) +#define I2C_STAT_RRDY (1UL << 3) +#define I2C_STAT_ARDY (1UL << 2) +#define I2C_STAT_NACK (1UL << 1) +#define I2C_STAT_AL (1UL << 0) + + + +#endif /* _OMAP3_I2C_H_ */ Index: sys/arm/cortexa8/omap3/omap3reg.h =================================================================== --- sys/arm/cortexa8/omap3/omap3reg.h (revision 0) +++ sys/arm/cortexa8/omap3/omap3reg.h (revision 0) @@ -0,0 +1,841 @@ +/* + * Copyright (c) 2010 + * Ben Gray . + * All rights reserved. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Ben Gray. + * 4. The name of the company nor the name of the author may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY BEN GRAY ``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 BEN GRAY 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. + */ + +/* + * Texas Instruments - OMAP3xxx series processors + * + * Reference: + * OMAP35x Applications Processor + * Technical Reference Manual + * (omap35xx_techref.pdf) + * + */ +#ifndef _OMAP3REG_H_ +#define _OMAP3REG_H_ + +#ifndef _LOCORE +#include /* for uint32_t */ +#endif + + + + +#define OMAP35XX_PERIPH_BASE 0x48000000UL +#define OMAP35XX_PERIPH_SIZE 0x01000000UL + +#define OMAP35XX_SDRAM0_START 0x80000000UL +#define OMAP35XX_SDRAM1_START 0xA0000000UL +#define OMAP35XX_SDRAM_BANKS 2 +#define OMAP35XX_SDRAM_BANK_SIZE 0x20000000UL + + +/* Physical/Virtual address for SDRAM controller */ + +#define OMAP35XX_SMS_VBASE 0x6C000000UL +#define OMAP35XX_SMS_HWBASE 0x6C000000UL +#define OMAP35XX_SMS_SIZE 0x01000000UL + +#define OMAP35XX_SDRC_VBASE 0x6D000000UL +#define OMAP35XX_SDRC_HWBASE 0x6D000000UL +#define OMAP35XX_SDRC_SIZE 0x01000000UL + + + +/* Physical/Virtual address for I/O space */ + +#define OMAP35XX_L3_VBASE 0x68000000UL +#define OMAP35XX_L3_HWBASE 0x68000000UL +#define OMAP35XX_L3_SIZE 0x01000000UL + +#define OMAP35XX_L4_CORE_VBASE 0x48000000UL +#define OMAP35XX_L4_CORE_HWBASE 0x48000000UL +#define OMAP35XX_L4_CORE_SIZE 0x01000000UL + +#define OMAP35XX_L4_WAKEUP_VBASE 0x48300000UL +#define OMAP35XX_L4_WAKEUP_HWBASE 0x48300000UL +#define OMAP35XX_L4_WAKEUP_SIZE 0x00040000UL + +#define OMAP35XX_L4_PERIPH_VBASE 0x49000000UL +#define OMAP35XX_L4_PERIPH_HWBASE 0x49000000UL +#define OMAP35XX_L4_PERIPH_SIZE 0x00100000UL + + +/* + * L4-CORE Physical/Virtual addresss offsets + */ +#define OMAP35XX_SCM_OFFSET 0x00002000UL +#define OMAP35XX_CM_OFFSET 0x00004000UL +#define OMAP35XX_SDMA_OFFSET 0x00056000UL +#define OMAP35XX_I2C3_OFFSET 0x00060000UL +#define OMAP35XX_USBTLL_OFFSET 0x00062000UL +#define OMAP35XX_USBHOST_OFFSET 0x00064000UL +#define OMAP35XX_UART1_OFFSET 0x0006A000UL +#define OMAP35XX_UART2_OFFSET 0x0006C000UL +#define OMAP35XX_I2C1_OFFSET 0x00070000UL +#define OMAP35XX_I2C2_OFFSET 0x00072000UL +#define OMAP35XX_MCBSP1_OFFSET 0x00074000UL +#define OMAP35XX_GPTIMER10_OFFSET 0x00086000UL +#define OMAP35XX_GPTIMER11_OFFSET 0x00088000UL +#define OMAP35XX_MCBSP5_OFFSET 0x00096000UL +#define OMAP35XX_MMU1_OFFSET 0x000BD400UL +#define OMAP35XX_INTCPS_OFFSET 0x00200000UL + + +/* + * L4-WAKEUP Physical/Virtual addresss offsets + */ +#define OMAP35XX_PRM_OFFSET 0x00006000UL +#define OMAP35XX_GPIO1_OFFSET 0x00010000UL +#define OMAP35XX_GPTIMER1_OFFSET 0x00018000UL + + + +/* + * L4-PERIPH Physical/Virtual addresss offsets + */ +#define OMAP35XX_UART3_OFFSET 0x00020000UL +#define OMAP35XX_MCBSP2_OFFSET 0x00022000UL +#define OMAP35XX_MCBSP3_OFFSET 0x00024000UL +#define OMAP35XX_MCBSP4_OFFSET 0x00026000UL +#define OMAP35XX_SIDETONE_MCBSP2_OFFSET 0x00028000UL +#define OMAP35XX_SIDETONE_MCBSP3_OFFSET 0x0002A000UL +#define OMAP35XX_GPTIMER2_OFFSET 0x00032000UL +#define OMAP35XX_GPTIMER3_OFFSET 0x00034000UL +#define OMAP35XX_GPTIMER4_OFFSET 0x00036000UL +#define OMAP35XX_GPTIMER5_OFFSET 0x00038000UL +#define OMAP35XX_GPTIMER6_OFFSET 0x0003A000UL +#define OMAP35XX_GPTIMER7_OFFSET 0x0003C000UL +#define OMAP35XX_GPTIMER8_OFFSET 0x0003E000UL +#define OMAP35XX_GPTIMER9_OFFSET 0x00040000UL +#define OMAP35XX_GPIO2_OFFSET 0x00050000UL +#define OMAP35XX_GPIO3_OFFSET 0x00052000UL +#define OMAP35XX_GPIO4_OFFSET 0x00054000UL +#define OMAP35XX_GPIO5_OFFSET 0x00056000UL +#define OMAP35XX_GPIO6_OFFSET 0x00058000UL + + + + + + +/* + * System Control Module + */ +#define OMAP35XX_SCM_HWBASE (OMAP35XX_L4_CORE_HWBASE + OMAP35XX_SCM_OFFSET) +#define OMAP35XX_SCM_VBASE (OMAP35XX_L4_CORE_VBASE + OMAP35XX_SCM_OFFSET) +#define OMAP35XX_SCM_SIZE 0x00001000UL + +#define OMAP35XX_SCM_REVISION 0x00000000UL +#define OMAP35XX_SCM_SYSCONFIG 0x00000010UL +#define OMAP35XX_SCM_PADCONFS_BASE 0x00000030UL +#define OMAP35XX_SCM_DEVCONF0 0x00000274UL +#define OMAP35XX_SCM_MEM_DFTRW0 0x00000278UL + + + + +/* + * + */ +#define OMAP35XX_CM_HWBASE (OMAP35XX_L4_CORE_HWBASE + OMAP35XX_CM_OFFSET) +#define OMAP35XX_CM_VBASE (OMAP35XX_L4_CORE_VBASE + OMAP35XX_CM_OFFSET) +#define OMAP35XX_CM_SIZE 0x00001500UL + +#define OMAP35XX_CM_CORE_OFFSET 0x00000A00UL +#define OMAP35XX_CM_CORE_SIZE 0x00000100UL +#define OMAP35XX_CM_FCLKEN1_CORE (OMAP35XX_CM_CORE_OFFSET + 0x0000UL) +#define OMAP35XX_CM_FCLKEN3_CORE (OMAP35XX_CM_CORE_OFFSET + 0x0008UL) +#define OMAP35XX_CM_ICLKEN1_CORE (OMAP35XX_CM_CORE_OFFSET + 0x0010UL) +#define OMAP35XX_CM_ICLKEN2_CORE (OMAP35XX_CM_CORE_OFFSET + 0x0014UL) +#define OMAP35XX_CM_ICLKEN3_CORE (OMAP35XX_CM_CORE_OFFSET + 0x0018UL) +#define OMAP35XX_CM_IDLEST1_CORE (OMAP35XX_CM_CORE_OFFSET + 0x0020UL) +#define OMAP35XX_CM_IDLEST2_CORE (OMAP35XX_CM_CORE_OFFSET + 0x0024UL) +#define OMAP35XX_CM_IDLEST3_CORE (OMAP35XX_CM_CORE_OFFSET + 0x0028UL) +#define OMAP35XX_CM_AUTOIDLE1_CORE (OMAP35XX_CM_CORE_OFFSET + 0x0030UL) +#define OMAP35XX_CM_AUTOIDLE2_CORE (OMAP35XX_CM_CORE_OFFSET + 0x0034UL) +#define OMAP35XX_CM_AUTOIDLE3_CORE (OMAP35XX_CM_CORE_OFFSET + 0x0038UL) +#define OMAP35XX_CM_CLKSEL_CORE (OMAP35XX_CM_CORE_OFFSET + 0x0040UL) +#define OMAP35XX_CM_CLKSTCTRL_CORE (OMAP35XX_CM_CORE_OFFSET + 0x0048UL) +#define OMAP35XX_CM_CLKSTST_CORE (OMAP35XX_CM_CORE_OFFSET + 0x004CUL) + +#define OMAP35XX_CM_WKUP_OFFSET 0x00000C00UL +#define OMAP35XX_CM_WKUP_SIZE 0x00000100UL +#define OMAP35XX_CM_FCLKEN_WKUP (OMAP35XX_CM_WKUP_OFFSET + 0x0000UL) +#define OMAP35XX_CM_ICLKEN_WKUP (OMAP35XX_CM_WKUP_OFFSET + 0x0010UL) +#define OMAP35XX_CM_IDLEST_WKUP (OMAP35XX_CM_WKUP_OFFSET + 0x0020UL) +#define OMAP35XX_CM_AUTOIDLE_WKUP (OMAP35XX_CM_WKUP_OFFSET + 0x0030UL) +#define OMAP35XX_CM_CLKSEL_WKUP (OMAP35XX_CM_WKUP_OFFSET + 0x0040UL) + +#define OMAP35XX_CM_PLL_OFFSET 0x00000D00UL +#define OMAP35XX_CM_PLL_SIZE 0x00000100UL +#define OMAP35XX_CM_CLKEN_PLL (OMAP35XX_CM_PLL_OFFSET + 0x0000UL) +#define OMAP35XX_CM_CLKEN2_PLL (OMAP35XX_CM_PLL_OFFSET + 0x0004UL) +#define OMAP35XX_CM_IDLEST_CKGEN (OMAP35XX_CM_PLL_OFFSET + 0x0020UL) +#define OMAP35XX_CM_IDLEST2_CKGEN (OMAP35XX_CM_PLL_OFFSET + 0x0024UL) +#define OMAP35XX_CM_AUTOIDLE_PLL (OMAP35XX_CM_PLL_OFFSET + 0x0030UL) +#define OMAP35XX_CM_AUTOIDLE2_PLL (OMAP35XX_CM_PLL_OFFSET + 0x0034UL) +#define OMAP35XX_CM_CLKSEL1_PLL (OMAP35XX_CM_PLL_OFFSET + 0x0040UL) +#define OMAP35XX_CM_CLKSEL2_PLL (OMAP35XX_CM_PLL_OFFSET + 0x0044UL) +#define OMAP35XX_CM_CLKSEL3_PLL (OMAP35XX_CM_PLL_OFFSET + 0x0048UL) +#define OMAP35XX_CM_CLKSEL4_PLL (OMAP35XX_CM_PLL_OFFSET + 0x004CUL) +#define OMAP35XX_CM_CLKSEL5_PLL (OMAP35XX_CM_PLL_OFFSET + 0x0050UL) +#define OMAP35XX_CM_CLKOUT_CTRL (OMAP35XX_CM_PLL_OFFSET + 0x0070UL) + +#define OMAP35XX_CM_PER_OFFSET 0x00001000UL +#define OMAP35XX_CM_PER_SIZE 0x00000100UL +#define OMAP35XX_CM_FCLKEN_PER (OMAP35XX_CM_PER_OFFSET + 0x0000UL) +#define OMAP35XX_CM_ICLKEN_PER (OMAP35XX_CM_PER_OFFSET + 0x0010UL) +#define OMAP35XX_CM_IDLEST_PER (OMAP35XX_CM_PER_OFFSET + 0x0020UL) +#define OMAP35XX_CM_AUTOIDLE_PER (OMAP35XX_CM_PER_OFFSET + 0x0030UL) +#define OMAP35XX_CM_CLKSEL_PER (OMAP35XX_CM_PER_OFFSET + 0x0040UL) +#define OMAP35XX_CM_SLEEPDEP_PER (OMAP35XX_CM_PER_OFFSET + 0x0044UL) +#define OMAP35XX_CM_CLKSTCTRL_PER (OMAP35XX_CM_PER_OFFSET + 0x0048UL) +#define OMAP35XX_CM_CLKSTST_PER (OMAP35XX_CM_PER_OFFSET + 0x004CUL) + +#define OMAP35XX_CM_USBHOST_OFFSET 0x00001400UL +#define OMAP35XX_CM_USBHOST_SIZE 0x00000100UL +#define OMAP35XX_CM_FCLKEN_USBHOST (OMAP35XX_CM_USBHOST_OFFSET + 0x0000UL) +#define OMAP35XX_CM_ICLKEN_USBHOST (OMAP35XX_CM_USBHOST_OFFSET + 0x0010UL) +#define OMAP35XX_CM_IDLEST_USBHOST (OMAP35XX_CM_USBHOST_OFFSET + 0x0020UL) +#define OMAP35XX_CM_AUTOIDLE_USBHOST (OMAP35XX_CM_USBHOST_OFFSET + 0x0030UL) +#define OMAP35XX_CM_SLEEPDEP_USBHOST (OMAP35XX_CM_USBHOST_OFFSET + 0x0044UL) +#define OMAP35XX_CM_CLKSTCTRL_USBHOST (OMAP35XX_CM_USBHOST_OFFSET + 0x0048UL) +#define OMAP35XX_CM_CLKSTST_USBHOST (OMAP35XX_CM_USBHOST_OFFSET + 0x004CUL) + + +/* + * + */ +#define OMAP35XX_PRM_HWBASE (OMAP35XX_L4_WAKEUP_HWBASE + OMAP35XX_PRM_OFFSET) +#define OMAP35XX_PRM_VBASE (OMAP35XX_L4_WAKEUP_VBASE + OMAP35XX_PRM_OFFSET) +#define OMAP35XX_PRM_SIZE 0x00001600UL + +#define OMAP35XX_PRM_CLKCTRL_OFFSET 0x00000D00UL +#define OMAP35XX_PRM_CLKCTRL_SIZE 0x00000100UL +#define OMAP35XX_PRM_CLKSEL (OMAP35XX_PRM_CLKCTRL_OFFSET + 0x0040UL) +#define OMAP35XX_PRM_CLKOUT_CTRL (OMAP35XX_PRM_CLKCTRL_OFFSET + 0x0070UL) + +#define OMAP35XX_PRM_GLOBAL_OFFSET 0x00001200UL +#define OMAP35XX_PRM_GLOBAL_SIZE 0x00000100UL +#define OMAP35XX_PRM_CLKSRC_CTRL (OMAP35XX_PRM_GLOBAL_OFFSET + 0x0070UL) + + + + + +/* + * Uarts + */ +#define OMAP35XX_UART1_HWBASE (OMAP35XX_L4_CORE_HWBASE + OMAP35XX_UART1_OFFSET) +#define OMAP35XX_UART1_VBASE (OMAP35XX_L4_CORE_VBASE + OMAP35XX_UART1_OFFSET) +#define OMAP35XX_UART1_SIZE 0x00001000UL + +#define OMAP35XX_UART2_HWBASE (OMAP35XX_L4_CORE_HWBASE + OMAP35XX_UART2_OFFSET) +#define OMAP35XX_UART2_VBASE (OMAP35XX_L4_CORE_VBASE + OMAP35XX_UART2_OFFSET) +#define OMAP35XX_UART2_SIZE 0x00001000UL + +#define OMAP35XX_UART3_HWBASE (OMAP35XX_L4_PERIPH_HWBASE + OMAP35XX_UART3_OFFSET) +#define OMAP35XX_UART3_VBASE (OMAP35XX_L4_PERIPH_VBASE + OMAP35XX_UART3_OFFSET) +#define OMAP35XX_UART3_SIZE 0x00001000UL + + +#define OMAP35XX_UART_FREQ 48000000 /* 48Mhz clock for all uarts (techref 17.3.1.1) */ + + + + +/* + * I2C Modules + */ +#define OMAP35XX_I2C1_HWBASE (OMAP35XX_L4_CORE_HWBASE + OMAP35XX_I2C1_OFFSET) +#define OMAP35XX_I2C1_VBASE (OMAP35XX_L4_CORE_VBASE + OMAP35XX_I2C1_OFFSET) +#define OMAP35XX_I2C1_SIZE 0x00000080UL + +#define OMAP35XX_I2C2_HWBASE (OMAP35XX_L4_CORE_HWBASE + OMAP35XX_I2C2_OFFSET) +#define OMAP35XX_I2C2_VBASE (OMAP35XX_L4_CORE_VBASE + OMAP35XX_I2C2_OFFSET) +#define OMAP35XX_I2C2_SIZE 0x00000080UL + +#define OMAP35XX_I2C3_HWBASE (OMAP35XX_L4_CORE_HWBASE + OMAP35XX_I2C3_OFFSET) +#define OMAP35XX_I2C3_VBASE (OMAP35XX_L4_CORE_VBASE + OMAP35XX_I2C3_OFFSET) +#define OMAP35XX_I2C3_SIZE 0x00000080UL + +#define OMAP35XX_I2C_IE 0x04 +#define OMAP35XX_I2C_STAT 0x08 +#define OMAP35XX_I2C_WE 0x0C +#define OMAP35XX_I2C_SYSS 0x10 +#define OMAP35XX_I2C_BUF 0x14 +#define OMAP35XX_I2C_CNT 0x18 +#define OMAP35XX_I2C_DATA 0x1C +#define OMAP35XX_I2C_SYSC 0x20 +#define OMAP35XX_I2C_CON 0x24 +#define OMAP35XX_I2C_OA0 0x28 +#define OMAP35XX_I2C_SA 0x2C +#define OMAP35XX_I2C_PSC 0x30 +#define OMAP35XX_I2C_SCLL 0x34 +#define OMAP35XX_I2C_SCLH 0x38 +#define OMAP35XX_I2C_SYSTEST 0x3C +#define OMAP35XX_I2C_BUFSTAT 0x40 +#define OMAP35XX_I2C_OA1 0x44 +#define OMAP35XX_I2C_OA2 0x48 +#define OMAP35XX_I2C_OA3 0x4C +#define OMAP35XX_I2C_ACTOA 0x50 +#define OMAP35XX_I2C_SBLOCK 0x54 + + + +/* + * McBSP Modules + */ +#define OMAP35XX_MCBSP1_HWBASE (OMAP35XX_L4_CORE_HWBASE + OMAP35XX_MCBSP1_OFFSET) +#define OMAP35XX_MCBSP1_VBASE (OMAP35XX_L4_CORE_VBASE + OMAP35XX_MCBSP1_OFFSET) +#define OMAP35XX_MCBSP1_SIZE 0x00001000UL + +#define OMAP35XX_MCBSP2_HWBASE (OMAP35XX_L4_PERIPH_HWBASE + OMAP35XX_MCBSP2_OFFSET) +#define OMAP35XX_MCBSP2_VBASE (OMAP35XX_L4_PERIPH_VBASE + OMAP35XX_MCBSP2_OFFSET) +#define OMAP35XX_MCBSP2_SIZE 0x00001000UL + +#define OMAP35XX_MCBSP3_HWBASE (OMAP35XX_L4_PERIPH_HWBASE + OMAP35XX_MCBSP3_OFFSET) +#define OMAP35XX_MCBSP3_VBASE (OMAP35XX_L4_PERIPH_VBASE + OMAP35XX_MCBSP3_OFFSET) +#define OMAP35XX_MCBSP3_SIZE 0x00001000UL + +#define OMAP35XX_MCBSP4_HWBASE (OMAP35XX_L4_PERIPH_HWBASE + OMAP35XX_MCBSP4_OFFSET) +#define OMAP35XX_MCBSP4_VBASE (OMAP35XX_L4_PERIPH_VBASE + OMAP35XX_MCBSP4_OFFSET) +#define OMAP35XX_MCBSP4_SIZE 0x00001000UL + +#define OMAP35XX_MCBSP5_HWBASE (OMAP35XX_L4_CORE_HWBASE + OMAP35XX_MCBSP5_OFFSET) +#define OMAP35XX_MCBSP5_VBASE (OMAP35XX_L4_CORE_VBASE + OMAP35XX_MCBSP5_OFFSET) +#define OMAP35XX_MCBSP5_SIZE 0x00001000UL + +#define OMAP35XX_MCBSP_DRR 0x0000 +#define OMAP35XX_MCBSP_DXR 0x0008 +#define OMAP35XX_MCBSP_SPCR2 0x0010 +#define OMAP35XX_MCBSP_SPCR1 0x0014 +#define OMAP35XX_MCBSP_RCR2 0x0018 +#define OMAP35XX_MCBSP_RCR1 0x001C +#define OMAP35XX_MCBSP_XCR2 0x0020 +#define OMAP35XX_MCBSP_XCR1 0x0024 +#define OMAP35XX_MCBSP_SRGR2 0x0028 +#define OMAP35XX_MCBSP_SRGR1 0x002C +#define OMAP35XX_MCBSP_MCR2 0x0030 +#define OMAP35XX_MCBSP_MCR1 0x0034 +#define OMAP35XX_MCBSP_RCERA 0x0038 +#define OMAP35XX_MCBSP_RCERB 0x003C +#define OMAP35XX_MCBSP_XCERA 0x0040 +#define OMAP35XX_MCBSP_XCERB 0x0044 +#define OMAP35XX_MCBSP_PCR 0x0048 +#define OMAP35XX_MCBSP_RCERC 0x004C +#define OMAP35XX_MCBSP_RCERD 0x0050 +#define OMAP35XX_MCBSP_XCERC 0x0054 +#define OMAP35XX_MCBSP_XCERD 0x0058 +#define OMAP35XX_MCBSP_RCERE 0x005C +#define OMAP35XX_MCBSP_RCERF 0x0060 +#define OMAP35XX_MCBSP_XCERE 0x0064 +#define OMAP35XX_MCBSP_XCERF 0x0068 +#define OMAP35XX_MCBSP_RCERG 0x006C +#define OMAP35XX_MCBSP_RCERH 0x0070 +#define OMAP35XX_MCBSP_XCERG 0x0074 +#define OMAP35XX_MCBSP_XCERH 0x0078 +#define OMAP35XX_MCBSP_RINTCLR 0x0080 +#define OMAP35XX_MCBSP_XINTCLR 0x0084 +#define OMAP35XX_MCBSP_ROVFLCLR 0x0088 +#define OMAP35XX_MCBSP_SYSCONFIG 0x008C +#define OMAP35XX_MCBSP_THRSH2 0x0090 +#define OMAP35XX_MCBSP_THRSH1 0x0094 +#define OMAP35XX_MCBSP_IRQSTATUS 0x00A0 +#define OMAP35XX_MCBSP_IRQENABLE 0x00A4 +#define OMAP35XX_MCBSP_WAKEUPEN 0x00A8 +#define OMAP35XX_MCBSP_XCCR 0x00AC +#define OMAP35XX_MCBSP_RCCR 0x00B0 +#define OMAP35XX_MCBSP_XBUFFSTAT 0x00B4 +#define OMAP35XX_MCBSP_RBUFFSTAT 0x00B8 +#define OMAP35XX_MCBSP_SSELCR 0x00BC +#define OMAP35XX_MCBSP_STATUS 0x00C0 + + + +/* + * USB TTL Module + */ +#define OMAP35XX_USBTLL_HWBASE (OMAP35XX_L4_CORE_HWBASE + OMAP35XX_USBTLL_OFFSET) +#define OMAP35XX_USBTLL_VBASE (OMAP35XX_L4_CORE_VBASE + OMAP35XX_USBTLL_OFFSET) +#define OMAP35XX_USBTLL_SIZE 0x00001000UL + +#define OMAP35XX_USBTLL_REVISION 0x0000 +#define OMAP35XX_USBTLL_SYSCONFIG 0x0010 +#define OMAP35XX_USBTLL_SYSSTATUS 0x0014 +#define OMAP35XX_USBTLL_IRQSTATUS 0x0018 +#define OMAP35XX_USBTLL_IRQENABLE 0x001C +#define OMAP35XX_USBTLL_TLL_SHARED_CONF 0x0030 +#define OMAP35XX_USBTLL_TLL_CHANNEL_CONF(i) (0x0040 + (0x04 * (i))) +#define OMAP35XX_USBTLL_ULPI_VENDOR_ID_LO(i) (0x0800 + (0x100 * (i))) +#define OMAP35XX_USBTLL_ULPI_VENDOR_ID_HI(i) (0x0801 + (0x100 * (i))) +#define OMAP35XX_USBTLL_ULPI_PRODUCT_ID_LO(i) (0x0802 + (0x100 * (i))) +#define OMAP35XX_USBTLL_ULPI_PRODUCT_ID_HI(i) (0x0803 + (0x100 * (i))) +#define OMAP35XX_USBTLL_ULPI_FUNCTION_CTRL(i) (0x0804 + (0x100 * (i))) +#define OMAP35XX_USBTLL_ULPI_FUNCTION_CTRL_SET(i) (0x0805 + (0x100 * (i))) +#define OMAP35XX_USBTLL_ULPI_FUNCTION_CTRL_CLR(i) (0x0806 + (0x100 * (i))) +#define OMAP35XX_USBTLL_ULPI_INTERFACE_CTRL(i) (0x0807 + (0x100 * (i))) +#define OMAP35XX_USBTLL_ULPI_INTERFACE_CTRL_SET(i) (0x0808 + (0x100 * (i))) +#define OMAP35XX_USBTLL_ULPI_INTERFACE_CTRL_CLR(i) (0x0809 + (0x100 * (i))) +#define OMAP35XX_USBTLL_ULPI_OTG_CTRL(i) (0x080A + (0x100 * (i))) +#define OMAP35XX_USBTLL_ULPI_OTG_CTRL_SET(i) (0x080B + (0x100 * (i))) +#define OMAP35XX_USBTLL_ULPI_OTG_CTRL_CLR(i) (0x080C + (0x100 * (i))) +#define OMAP35XX_USBTLL_ULPI_USB_INT_EN_RISE(i) (0x080D + (0x100 * (i))) +#define OMAP35XX_USBTLL_ULPI_USB_INT_EN_RISE_SET(i) (0x080E + (0x100 * (i))) +#define OMAP35XX_USBTLL_ULPI_USB_INT_EN_RISE_CLR(i) (0x080F + (0x100 * (i))) +#define OMAP35XX_USBTLL_ULPI_USB_INT_EN_FALL(i) (0x0810 + (0x100 * (i))) +#define OMAP35XX_USBTLL_ULPI_USB_INT_EN_FALL_SET(i) (0x0811 + (0x100 * (i))) +#define OMAP35XX_USBTLL_ULPI_USB_INT_EN_FALL_CLR(i) (0x0812 + (0x100 * (i))) +#define OMAP35XX_USBTLL_ULPI_USB_INT_STATUS(i) (0x0813 + (0x100 * (i))) +#define OMAP35XX_USBTLL_ULPI_USB_INT_LATCH(i) (0x0814 + (0x100 * (i))) +#define OMAP35XX_USBTLL_ULPI_DEBUG(i) (0x0815 + (0x100 * (i))) +#define OMAP35XX_USBTLL_ULPI_SCRATCH_REGISTER(i) (0x0816 + (0x100 * (i))) +#define OMAP35XX_USBTLL_ULPI_SCRATCH_REGISTER_SET(i) (0x0817 + (0x100 * (i))) +#define OMAP35XX_USBTLL_ULPI_SCRATCH_REGISTER_CLR(i) (0x0818 + (0x100 * (i))) +#define OMAP35XX_USBTLL_ULPI_EXTENDED_SET_ACCESS(i) (0x082F + (0x100 * (i))) +#define OMAP35XX_USBTLL_ULPI_UTMI_VCONTROL_EN(i) (0x0830 + (0x100 * (i))) +#define OMAP35XX_USBTLL_ULPI_UTMI_VCONTROL_EN_SET(i) (0x0831 + (0x100 * (i))) +#define OMAP35XX_USBTLL_ULPI_UTMI_VCONTROL_EN_CLR(i) (0x0832 + (0x100 * (i))) +#define OMAP35XX_USBTLL_ULPI_UTMI_VCONTROL_STATUS(i) (0x0833 + (0x100 * (i))) +#define OMAP35XX_USBTLL_ULPI_UTMI_VCONTROL_LATCH(i) (0x0834 + (0x100 * (i))) +#define OMAP35XX_USBTLL_ULPI_UTMI_VSTATUS(i) (0x0835 + (0x100 * (i))) +#define OMAP35XX_USBTLL_ULPI_UTMI_VSTATUS_SET(i) (0x0836 + (0x100 * (i))) +#define OMAP35XX_USBTLL_ULPI_UTMI_VSTATUS_CLR(i) (0x0837 + (0x100 * (i))) +#define OMAP35XX_USBTLL_ULPI_USB_INT_LATCH_NOCLR(i) (0x0838 + (0x100 * (i))) +#define OMAP35XX_USBTLL_ULPI_VENDOR_INT_EN(i) (0x083B + (0x100 * (i))) +#define OMAP35XX_USBTLL_ULPI_VENDOR_INT_EN_SET(i) (0x083C + (0x100 * (i))) +#define OMAP35XX_USBTLL_ULPI_VENDOR_INT_EN_CLR(i) (0x083D + (0x100 * (i))) +#define OMAP35XX_USBTLL_ULPI_VENDOR_INT_STATUS(i) (0x083E + (0x100 * (i))) +#define OMAP35XX_USBTLL_ULPI_VENDOR_INT_LATCH(i) (0x083F + (0x100 * (i))) + + +/* + * USB Host Module + */ +#define OMAP35XX_USBHOST_HWBASE (OMAP35XX_L4_CORE_HWBASE + OMAP35XX_USBHOST_OFFSET) +#define OMAP35XX_USBHOST_VBASE (OMAP35XX_L4_CORE_VBASE + OMAP35XX_USBHOST_OFFSET) +#define OMAP35XX_USBHOST_SIZE 0x00001000UL + +/* UHH */ +#define OMAP35XX_USBHOST_UHH_REVISION 0x0000 +#define OMAP35XX_USBHOST_UHH_SYSCONFIG 0x0010 +#define OMAP35XX_USBHOST_UHH_SYSSTATUS 0x0014 +#define OMAP35XX_USBHOST_UHH_HOSTCONFIG 0x0040 +#define OMAP35XX_USBHOST_UHH_DEBUG_CSR 0x0044 + +/* OHCI */ +#define OMAP35XX_USBHOST_HCREVISION 0x0400 +#define OMAP35XX_USBHOST_HCCONTROL 0x0404 +#define OMAP35XX_USBHOST_HCCOMMANDSTATUS 0x0408 +#define OMAP35XX_USBHOST_HCINTERRUPTSTATUS 0x040C +#define OMAP35XX_USBHOST_HCINTERRUPTENABLE 0x0410 +#define OMAP35XX_USBHOST_HCINTERRUPTDISABLE 0x0414 +#define OMAP35XX_USBHOST_HCHCCA 0x0418 +#define OMAP35XX_USBHOST_HCPERIODCURRENTED 0x041C +#define OMAP35XX_USBHOST_HCCONTROLHEADED 0x0420 +#define OMAP35XX_USBHOST_HCCONTROLCURRENTED 0x0424 +#define OMAP35XX_USBHOST_HCBULKHEADED 0x0428 +#define OMAP35XX_USBHOST_HCBULKCURRENTED 0x042C +#define OMAP35XX_USBHOST_HCDONEHEAD 0x0430 +#define OMAP35XX_USBHOST_HCFMINTERVAL 0x0434 +#define OMAP35XX_USBHOST_HCFMREMAINING 0x0438 +#define OMAP35XX_USBHOST_HCFMNUMBER 0x043C +#define OMAP35XX_USBHOST_HCPERIODICSTART 0x0440 +#define OMAP35XX_USBHOST_HCLSTHRESHOLD 0x0444 +#define OMAP35XX_USBHOST_HCRHDESCRIPTORA 0x0448 +#define OMAP35XX_USBHOST_HCRHDESCRIPTORB 0x044C +#define OMAP35XX_USBHOST_HCRHSTATUS 0x0450 +#define OMAP35XX_USBHOST_HCRHPORTSTATUS_1 0x0454 +#define OMAP35XX_USBHOST_HCRHPORTSTATUS_2 0x0458 +#define OMAP35XX_USBHOST_HCRHPORTSTATUS_3 0x045C + +/* EHCI */ +#define OMAP35XX_USBHOST_HCCAPBASE 0x0800 +#define OMAP35XX_USBHOST_HCSPARAMS 0x0804 +#define OMAP35XX_USBHOST_HCCPARAMS 0x0808 +#define OMAP35XX_USBHOST_USBCMD 0x0810 +#define OMAP35XX_USBHOST_USBSTS 0x0814 +#define OMAP35XX_USBHOST_USBINTR 0x0818 +#define OMAP35XX_USBHOST_FRINDEX 0x081C +#define OMAP35XX_USBHOST_CTRLDSSEGMENT 0x0820 +#define OMAP35XX_USBHOST_PERIODICLISTBASE 0x0824 +#define OMAP35XX_USBHOST_ASYNCLISTADDR 0x0828 +#define OMAP35XX_USBHOST_CONFIGFLAG 0x0850 +#define OMAP35XX_USBHOST_PORTSC(i) (0x0854 + (0x04 * (i))) +#define OMAP35XX_USBHOST_INSNREG00 0x0890 +#define OMAP35XX_USBHOST_INSNREG01 0x0894 +#define OMAP35XX_USBHOST_INSNREG02 0x0898 +#define OMAP35XX_USBHOST_INSNREG03 0x089C +#define OMAP35XX_USBHOST_INSNREG04 0x08A0 +#define OMAP35XX_USBHOST_INSNREG05_UTMI 0x08A4 +#define OMAP35XX_USBHOST_INSNREG05_ULPI 0x08A4 + + + + +/* + * SDRAM Controler (SDRC) + * PA 0x6D00_0000 + */ + +#define OMAP35XX_SDRC_SYSCONFIG (OMAP35XX_SDRC_VBASE + 0x10) +#define OMAP35XX_SDRC_SYSSTATUS (OMAP35XX_SDRC_VBASE + 0x14) +#define OMAP35XX_SDRC_CS_CFG (OMAP35XX_SDRC_VBASE + 0x40) +#define OMAP35XX_SDRC_SHARING (OMAP35XX_SDRC_VBASE + 0x44) +#define OMAP35XX_SDRC_ERR_ADDR (OMAP35XX_SDRC_VBASE + 0x48) +#define OMAP35XX_SDRC_ERR_TYPE (OMAP35XX_SDRC_VBASE + 0x4C) +#define OMAP35XX_SDRC_DLLA_CTRL (OMAP35XX_SDRC_VBASE + 0x60) +#define OMAP35XX_SDRC_DLLA_STATUS (OMAP35XX_SDRC_VBASE + 0x64) +#define OMAP35XX_SDRC_POWER_REG (OMAP35XX_SDRC_VBASE + 0x70) +#define OMAP35XX_SDRC_MCFG(p) (OMAP35XX_SDRC_VBASE + 0x80 + (0x30 * (p))) +#define OMAP35XX_SDRC_MR(p) (OMAP35XX_SDRC_VBASE + 0x84 + (0x30 * (p))) +#define OMAP35XX_SDRC_EMR2(p) (OMAP35XX_SDRC_VBASE + 0x8C + (0x30 * (p))) +#define OMAP35XX_SDRC_ACTIM_CTRLA(p) (OMAP35XX_SDRC_VBASE + 0x9C + (0x28 * (p))) +#define OMAP35XX_SDRC_ACTIM_CTRLB(p) (OMAP35XX_SDRC_VBASE + 0xA0 + (0x28 * (p))) +#define OMAP35XX_SDRC_RFR_CTRL(p) (OMAP35XX_SDRC_VBASE + 0xA4 + (0x30 * (p))) +#define OMAP35XX_SDRC_MANUAL(p) (OMAP35XX_SDRC_VBASE + 0xA8 + (0x30 * (p))) + + +/* + * SDMA Offset + * PA 0x4805 6000 + */ + +#define OMAP35XX_SDMA_HWBASE (OMAP35XX_L4_CORE_HWBASE + OMAP35XX_SDMA_OFFSET) +#define OMAP35XX_SDMA_VBASE (OMAP35XX_L4_CORE_VBASE + OMAP35XX_SDMA_OFFSET) +#define OMAP35XX_SDMA_SIZE 0x00001000UL + +#define OMAP35XX_SDMA_IRQSTATUS_L(j) (0x0008 + ((j) * 0x4)) +#define OMAP35XX_SDMA_IRQENABLE_L(j) (0x0018 + ((j) * 0x4)) +#define OMAP35XX_SDMA_SYSSTATUS 0x0028 +#define OMAP35XX_SDMA_OCP_SYSCONFIG 0x002C +#define OMAP35XX_SDMA_CAPS_0 0x0064 +#define OMAP35XX_SDMA_CAPS_2 0x006C +#define OMAP35XX_SDMA_CAPS_3 0x0070 +#define OMAP35XX_SDMA_CAPS_4 0x0074 +#define OMAP35XX_SDMA_GCR 0x0078 +#define OMAP35XX_SDMA_CCR(i) (0x0080 + ((i) * 0x60)) +#define OMAP35XX_SDMA_CLNK_CTRL(i) (0x0084 + ((i) * 0x60)) +#define OMAP35XX_SDMA_CICR(i) (0x0088 + ((i) * 0x60)) +#define OMAP35XX_SDMA_CSR(i) (0x008C + ((i) * 0x60)) +#define OMAP35XX_SDMA_CSDP(i) (0x0090 + ((i) * 0x60)) +#define OMAP35XX_SDMA_CEN(i) (0x0094 + ((i) * 0x60)) +#define OMAP35XX_SDMA_CFN(i) (0x0098 + ((i) * 0x60)) +#define OMAP35XX_SDMA_CSSA(i) (0x009C + ((i) * 0x60)) +#define OMAP35XX_SDMA_CDSA(i) (0x00A0 + ((i) * 0x60)) +#define OMAP35XX_SDMA_CSE(i) (0x00A4 + ((i) * 0x60)) +#define OMAP35XX_SDMA_CSF(i) (0x00A8 + ((i) * 0x60)) +#define OMAP35XX_SDMA_CDE(i) (0x00AC + ((i) * 0x60)) +#define OMAP35XX_SDMA_CDF(i) (0x00B0 + ((i) * 0x60)) +#define OMAP35XX_SDMA_CSAC(i) (0x00B4 + ((i) * 0x60)) +#define OMAP35XX_SDMA_CDAC(i) (0x00B8 + ((i) * 0x60)) +#define OMAP35XX_SDMA_CCEN(i) (0x00BC + ((i) * 0x60)) +#define OMAP35XX_SDMA_CCFN(i) (0x00C0 + ((i) * 0x60)) +#define OMAP35XX_SDMA_COLOR(i) (0x00C4 + ((i) * 0x60)) + + + +/* + * Interrupt Controller Unit. + * PA 0x4820_0000 + */ + +#define OMAP35XX_INTCPS_HWBASE (OMAP35XX_L4_CORE_HWBASE + OMAP35XX_INTCPS_OFFSET) +#define OMAP35XX_INTCPS_VBASE (OMAP35XX_L4_CORE_VBASE + OMAP35XX_INTCPS_OFFSET) +#define OMAP35XX_INTCPS_SIZE 0x00001000UL + +#define OMAP35XX_INTCPS_SYSCONFIG (OMAP35XX_INTCPS_VBASE + 0x10) +#define OMAP35XX_INTCPS_SYSSTATUS (OMAP35XX_INTCPS_VBASE + 0x14) +#define OMAP35XX_INTCPS_SIR_IRQ (OMAP35XX_INTCPS_VBASE + 0x40) +#define OMAP35XX_INTCPS_SIR_FIQ (OMAP35XX_INTCPS_VBASE + 0x44) +#define OMAP35XX_INTCPS_CONTROL (OMAP35XX_INTCPS_VBASE + 0x48) +#define OMAP35XX_INTCPS_PROTECTION (OMAP35XX_INTCPS_VBASE + 0x4C) +#define OMAP35XX_INTCPS_IDLE (OMAP35XX_INTCPS_VBASE + 0x50) +#define OMAP35XX_INTCPS_IRQ_PRIORITY (OMAP35XX_INTCPS_VBASE + 0x60) +#define OMAP35XX_INTCPS_FIQ_PRIORITY (OMAP35XX_INTCPS_VBASE + 0x64) +#define OMAP35XX_INTCPS_THRESHOLD (OMAP35XX_INTCPS_VBASE + 0x68) +#define OMAP35XX_INTCPS_ITR(n) (OMAP35XX_INTCPS_VBASE + 0x80 + (0x20 * (n))) +#define OMAP35XX_INTCPS_MIR(n) (OMAP35XX_INTCPS_VBASE + 0x84 + (0x20 * (n))) +#define OMAP35XX_INTCPS_MIR_CLEAR(n) (OMAP35XX_INTCPS_VBASE + 0x88 + (0x20 * (n))) +#define OMAP35XX_INTCPS_MIR_SET(n) (OMAP35XX_INTCPS_VBASE + 0x8C + (0x20 * (n))) +#define OMAP35XX_INTCPS_ISR_SET(n) (OMAP35XX_INTCPS_VBASE + 0x90 + (0x20 * (n))) +#define OMAP35XX_INTCPS_ISR_CLEAR(n) (OMAP35XX_INTCPS_VBASE + 0x94 + (0x20 * (n))) +#define OMAP35XX_INTCPS_PENDING_IRQ(n) (OMAP35XX_INTCPS_VBASE + 0x98 + (0x20 * (n))) +#define OMAP35XX_INTCPS_PENDING_FIQ(n) (OMAP35XX_INTCPS_VBASE + 0x9C + (0x20 * (n))) +#define OMAP35XX_INTCPS_ILR(m) (OMAP35XX_INTCPS_VBASE + 0x100 + (0x4 * (m))) + + +#define OMAP35XX_IRQ_EMUINT 0 /* MPU emulation(2) */ +#define OMAP35XX_IRQ_COMMTX 1 /* MPU emulation(2) */ +#define OMAP35XX_IRQ_COMMRX 2 /* MPU emulation(2) */ +#define OMAP35XX_IRQ_BENCH 3 /* MPU emulation(2) */ +#define OMAP35XX_IRQ_MCBSP2_ST 4 /* Sidetone MCBSP2 overflow */ +#define OMAP35XX_IRQ_MCBSP3_ST 5 /* Sidetone MCBSP3 overflow */ +#define OMAP35XX_IRQ_SSM_ABORT 6 /* MPU subsystem secure state-machine abort (2) */ +#define OMAP35XX_IRQ_SYS_NIRQ 7 /* External source (active low) */ +#define OMAP35XX_IRQ_RESERVED8 8 /* RESERVED */ +#define OMAP35XX_IRQ_SMX_DBG 9 /* SMX error for debug */ +#define OMAP35XX_IRQ_SMX_APP 10 /* SMX error for application */ +#define OMAP35XX_IRQ_PRCM_MPU 11 /* PRCM module IRQ */ +#define OMAP35XX_IRQ_SDMA0 12 /* System DMA request 0(3) */ +#define OMAP35XX_IRQ_SDMA1 13 /* System DMA request 1(3) */ +#define OMAP35XX_IRQ_SDMA2 14 /* System DMA request 2 */ +#define OMAP35XX_IRQ_SDMA3 15 /* System DMA request 3 */ +#define OMAP35XX_IRQ_MCBSP1 16 /* McBSP module 1 IRQ (3) */ +#define OMAP35XX_IRQ_MCBSP2 17 /* McBSP module 2 IRQ (3) */ +#define OMAP35XX_IRQ_SR1 18 /* SmartReflex™ 1 */ +#define OMAP35XX_IRQ_SR2 19 /* SmartReflex™ 2 */ +#define OMAP35XX_IRQ_GPMC 20 /* General-purpose memory controller module */ +#define OMAP35XX_IRQ_SGX 21 /* 2D/3D graphics module */ +#define OMAP35XX_IRQ_MCBSP3 22 /* McBSP module 3(3) */ +#define OMAP35XX_IRQ_MCBSP4 23 /* McBSP module 4(3) */ +#define OMAP35XX_IRQ_CAM0 24 /* Camera interface request 0 */ +#define OMAP35XX_IRQ_DSS 25 /* Display subsystem module(3) */ +#define OMAP35XX_IRQ_MAIL_U0 26 /* Mailbox user 0 request */ +#define OMAP35XX_IRQ_MCBSP5_IRQ1 27 /* McBSP module 5 (3) */ +#define OMAP35XX_IRQ_IVA2_MMU 28 /* IVA2 MMU */ +#define OMAP35XX_IRQ_GPIO1_MPU 29 /* GPIO module 1(3) */ +#define OMAP35XX_IRQ_GPIO2_MPU 30 /* GPIO module 2(3) */ +#define OMAP35XX_IRQ_GPIO3_MPU 31 /* GPIO module 3(3) */ +#define OMAP35XX_IRQ_GPIO4_MPU 32 /* GPIO module 4(3) */ +#define OMAP35XX_IRQ_GPIO5_MPU 33 /* GPIO module 5(3) */ +#define OMAP35XX_IRQ_GPIO6_MPU 34 /* GPIO module 6(3) */ +#define OMAP35XX_IRQ_USIM 35 /* USIM interrupt (HS devices only) (4) */ +#define OMAP35XX_IRQ_WDT3 36 /* Watchdog timer module 3 overflow */ +#define OMAP35XX_IRQ_GPT1 37 /* General-purpose timer module 1 */ +#define OMAP35XX_IRQ_GPT2 38 /* General-purpose timer module 2 */ +#define OMAP35XX_IRQ_GPT3 39 /* General-purpose timer module 3 */ +#define OMAP35XX_IRQ_GPT4 40 /* General-purpose timer module 4 */ +#define OMAP35XX_IRQ_GPT5 41 /* General-purpose timer module 5(3) */ +#define OMAP35XX_IRQ_GPT6 42 /* General-purpose timer module 6(3) */ +#define OMAP35XX_IRQ_GPT7 43 /* General-purpose timer module 7(3) */ +#define OMAP35XX_IRQ_GPT8 44 /* General-purpose timer module 8(3) */ +#define OMAP35XX_IRQ_GPT9 45 /* General-purpose timer module 9 */ +#define OMAP35XX_IRQ_GPT10 46 /* General-purpose timer module 10 */ +#define OMAP35XX_IRQ_GPT11 47 /* General-purpose timer module 11 */ +#define OMAP35XX_IRQ_SPI4 48 /* McSPI module 4 */ +#define OMAP35XX_IRQ_SHA1MD5_2 49 /* SHA-1/MD5 crypto-accelerator 2 (HS devices only)(4) */ +#define OMAP35XX_IRQ_FPKA_IRQREADY_N 50 /* PKA crypto-accelerator (HS devices only) (4) */ +#define OMAP35XX_IRQ_SHA2MD5 51 /* SHA-2/MD5 crypto-accelerator 1 (HS devices only) (4) */ +#define OMAP35XX_IRQ_RNG 52 /* RNG module (HS devices only) (4) */ +#define OMAP35XX_IRQ_MG 53 /* MG function (3) */ +#define OMAP35XX_IRQ_MCBSP4_TX 54 /* McBSP module 4 transmit(3) */ +#define OMAP35XX_IRQ_MCBSP4_RX 55 /* McBSP module 4 receive(3) */ +#define OMAP35XX_IRQ_I2C1 56 /* I2C module 1 */ +#define OMAP35XX_IRQ_I2C2 57 /* I2C module 2 */ +#define OMAP35XX_IRQ_HDQ 58 /* HDQ / One-wire */ +#define OMAP35XX_IRQ_MCBSP1_TX 59 /* McBSP module 1 transmit(3) */ +#define OMAP35XX_IRQ_MCBSP1_RX 60 /* McBSP module 1 receive(3) */ +#define OMAP35XX_IRQ_I2C3 61 /* I2C module 3 */ +#define OMAP35XX_IRQ_McBSP2_TX 62 /* McBSP module 2 transmit(3) */ +#define OMAP35XX_IRQ_McBSP2_RX 63 /* McBSP module 2 receive(3) */ +#define OMAP35XX_IRQ_FPKA_IRQRERROR_N 64 /* PKA crypto-accelerator (HS devices only) (4) */ +#define OMAP35XX_IRQ_SPI1 65 /* McSPI module 1 */ +#define OMAP35XX_IRQ_SPI2 66 /* McSPI module 2 */ +#define OMAP35XX_IRQ_RESERVED67 67 /* RESERVED */ +#define OMAP35XX_IRQ_RESERVED68 68 /* RESERVED */ +#define OMAP35XX_IRQ_RESERVED69 69 /* RESERVED */ +#define OMAP35XX_IRQ_RESERVED70 70 /* RESERVED */ +#define OMAP35XX_IRQ_RESERVED71 71 /* RESERVED */ +#define OMAP35XX_IRQ_UART1 72 /* UART module 1 */ +#define OMAP35XX_IRQ_UART2 73 /* UART module 2 */ +#define OMAP35XX_IRQ_UART3 74 /* UART module 3 (also infrared)(3) */ +#define OMAP35XX_IRQ_PBIAS 75 /* Merged interrupt for PBIASlite1 and 2 */ +#define OMAP35XX_IRQ_OHCI 76 /* OHCI controller HSUSB MP Host Interrupt */ +#define OMAP35XX_IRQ_EHCI 77 /* EHCI controller HSUSB MP Host Interrupt */ +#define OMAP35XX_IRQ_TLL 78 /* HSUSB MP TLL Interrupt */ +#define OMAP35XX_IRQ_PARTHASH 79 /* SHA2/MD5 crypto-accelerator 1 (HS devices only) (4) */ +#define OMAP35XX_IRQ_RESERVED80 80 /* Reserved */ +#define OMAP35XX_IRQ_MCBSP5_TX 81 /* McBSP module 5 transmit(3) */ +#define OMAP35XX_IRQ_MCBSP5_RX 82 /* McBSP module 5 receive(3) */ +#define OMAP35XX_IRQ_MMC1 83 /* MMC/SD module 1 */ +#define OMAP35XX_IRQ_MS 84 /* MS-PRO™ module */ +#define OMAP35XX_IRQ_RESERVED85 85 /* Reserved */ +#define OMAP35XX_IRQ_MMC2 86 /* MMC/SD module 2 */ +#define OMAP35XX_IRQ_MPU_ICR 87 /* MPU ICR */ +#define OMAP35XX_IRQ_RESERVED 88 /* RESERVED */ +#define OMAP35XX_IRQ_MCBSP3_TX 89 /* McBSP module 3 transmit(3) */ +#define OMAP35XX_IRQ_MCBSP3_RX 90 /* McBSP module 3 receive(3) */ +#define OMAP35XX_IRQ_SPI3 91 /* McSPI module 3 */ +#define OMAP35XX_IRQ_HSUSB_MC_NINT 92 /* High-Speed USB OTG controller */ +#define OMAP35XX_IRQ_HSUSB_DMA_NINT 93 /* High-Speed USB OTG DMA controller */ +#define OMAP35XX_IRQ_MMC3 94 /* MMC/SD module 3 */ +#define OMAP35XX_IRQ_GPT12 95 /* General-purpose timer module 12 */ + + + + +/* + * General Purpose Timers + */ +#define OMAP35XX_GPTIMER1_VBASE (OMAP35XX_L4_WAKEUP_VBASE + OMAP35XX_GPTIMER1_OFFSET) +#define OMAP35XX_GPTIMER2_VBASE (OMAP35XX_L4_PERIPH_VBASE + OMAP35XX_GPTIMER2_OFFSET) +#define OMAP35XX_GPTIMER3_VBASE (OMAP35XX_L4_PERIPH_VBASE + OMAP35XX_GPTIMER3_OFFSET) +#define OMAP35XX_GPTIMER4_VBASE (OMAP35XX_L4_PERIPH_VBASE + OMAP35XX_GPTIMER4_OFFSET) +#define OMAP35XX_GPTIMER5_VBASE (OMAP35XX_L4_PERIPH_VBASE + OMAP35XX_GPTIMER5_OFFSET) +#define OMAP35XX_GPTIMER6_VBASE (OMAP35XX_L4_PERIPH_VBASE + OMAP35XX_GPTIMER6_OFFSET) +#define OMAP35XX_GPTIMER7_VBASE (OMAP35XX_L4_PERIPH_VBASE + OMAP35XX_GPTIMER7_OFFSET) +#define OMAP35XX_GPTIMER8_VBASE (OMAP35XX_L4_PERIPH_VBASE + OMAP35XX_GPTIMER8_OFFSET) +#define OMAP35XX_GPTIMER9_VBASE (OMAP35XX_L4_PERIPH_VBASE + OMAP35XX_GPTIMER9_OFFSET) +#define OMAP35XX_GPTIMER10_VBASE (OMAP35XX_L4_CORE_VBASE + OMAP35XX_GPTIMER10_OFFSET) +#define OMAP35XX_GPTIMER11_VBASE (OMAP35XX_L4_CORE_VBASE + OMAP35XX_GPTIMER11_OFFSET) +#define OMAP35XX_GPTIMER12_VBASE 0x48304000UL /* GPTIMER12 */ +#define OMAP35XX_GPTIMER_SIZE 0x00001000UL + +#define OMAP35XX_GPTIMER10_HWBASE (OMAP35XX_L4_CORE_HWBASE + OMAP35XX_GPTIMER10_OFFSET) +#define OMAP35XX_GPTIMER11_HWBASE (OMAP35XX_L4_CORE_HWBASE + OMAP35XX_GPTIMER11_OFFSET) + + +/* Timer register offsets */ +#define OMAP35XX_GPTIMER_TIOCP_CFG 0x010 +#define OMAP35XX_GPTIMER_TISTAT 0x014 +#define OMAP35XX_GPTIMER_TISR 0x018 +#define OMAP35XX_GPTIMER_TIER 0x01C +#define OMAP35XX_GPTIMER_TWER 0x020 +#define OMAP35XX_GPTIMER_TCLR 0x024 +#define OMAP35XX_GPTIMER_TCRR 0x028 +#define OMAP35XX_GPTIMER_TLDR 0x02C +#define OMAP35XX_GPTIMER_TTGR 0x030 +#define OMAP35XX_GPTIMER_TWPS 0x034 +#define OMAP35XX_GPTIMER_TMAR 0x038 +#define OMAP35XX_GPTIMER_TCAR1 0x03C +#define OMAP35XX_GPTIMER_TSICR 0x040 +#define OMAP35XX_GPTIMER_TCAR2 0x044 +#define OMAP35XX_GPTIMER_TPIR 0x048 +#define OMAP35XX_GPTIMER_TNIR 0x04C +#define OMAP35XX_GPTIMER_TCVR 0x050 +#define OMAP35XX_GPTIMER_TOCR 0x054 +#define OMAP35XX_GPTIMER_TOWR 0x058 + +/* Bit values */ +#define MAT_IT_FLAG 0x01 +#define OVF_IT_FLAG 0x02 +#define TCAR_IT_FLAG 0x04 + + + +/* + * GPIO - General Purpose IO + */ + +/* Base addresses for the GPIO modules */ +#define OMAP35XX_GPIO1_HWBASE (OMAP35XX_L4_WAKEUP_HWBASE + OMAP35XX_GPIO1_OFFSET) +#define OMAP35XX_GPIO1_VBASE (OMAP35XX_L4_WAKEUP_VBASE + OMAP35XX_GPIO1_OFFSET) +#define OMAP35XX_GPIO1_SIZE 0x00001000UL +#define OMAP35XX_GPIO2_HWBASE (OMAP35XX_L4_PERIPH_HWBASE + OMAP35XX_GPIO2_OFFSET) +#define OMAP35XX_GPIO2_VBASE (OMAP35XX_L4_PERIPH_VBASE + OMAP35XX_GPIO2_OFFSET) +#define OMAP35XX_GPIO2_SIZE 0x00001000UL +#define OMAP35XX_GPIO3_HWBASE (OMAP35XX_L4_PERIPH_HWBASE + OMAP35XX_GPIO3_OFFSET) +#define OMAP35XX_GPIO3_VBASE (OMAP35XX_L4_PERIPH_VBASE + OMAP35XX_GPIO3_OFFSET) +#define OMAP35XX_GPIO3_SIZE 0x00001000UL +#define OMAP35XX_GPIO4_HWBASE (OMAP35XX_L4_PERIPH_HWBASE + OMAP35XX_GPIO4_OFFSET) +#define OMAP35XX_GPIO4_VBASE (OMAP35XX_L4_PERIPH_VBASE + OMAP35XX_GPIO4_OFFSET) +#define OMAP35XX_GPIO4_SIZE 0x00001000UL +#define OMAP35XX_GPIO5_HWBASE (OMAP35XX_L4_PERIPH_HWBASE + OMAP35XX_GPIO5_OFFSET) +#define OMAP35XX_GPIO5_VBASE (OMAP35XX_L4_PERIPH_VBASE + OMAP35XX_GPIO5_OFFSET) +#define OMAP35XX_GPIO5_SIZE 0x00001000UL +#define OMAP35XX_GPIO6_HWBASE (OMAP35XX_L4_PERIPH_HWBASE + OMAP35XX_GPIO6_OFFSET) +#define OMAP35XX_GPIO6_VBASE (OMAP35XX_L4_PERIPH_VBASE + OMAP35XX_GPIO6_OFFSET) +#define OMAP35XX_GPIO6_SIZE 0x00001000UL + + + +/* Register offsets within the banks above */ +#define OMAP35XX_GPIO_SYSCONFIG 0x010 +#define OMAP35XX_GPIO_SYSSTATUS 0x014 +#define OMAP35XX_GPIO_IRQSTATUS1 0x018 +#define OMAP35XX_GPIO_IRQENABLE1 0x01C +#define OMAP35XX_GPIO_WAKEUPENABLE 0x020 +#define OMAP35XX_GPIO_IRQSTATUS2 0x028 +#define OMAP35XX_GPIO_IRQENABLE2 0x02C +#define OMAP35XX_GPIO_CTRL 0x030 +#define OMAP35XX_GPIO_OE 0x034 +#define OMAP35XX_GPIO_DATAIN 0x038 +#define OMAP35XX_GPIO_DATAOUT 0x03C +#define OMAP35XX_GPIO_LEVELDETECT0 0x040 +#define OMAP35XX_GPIO_LEVELDETECT1 0x044 +#define OMAP35XX_GPIO_RISINGDETECT 0x048 +#define OMAP35XX_GPIO_FALLINGDETECT 0x04C +#define OMAP35XX_GPIO_DEBOUNCENABLE 0x050 +#define OMAP35XX_GPIO_DEBOUNCINGTIME 0x054 +#define OMAP35XX_GPIO_CLEARIRQENABLE1 0x060 +#define OMAP35XX_GPIO_SETIRQENABLE1 0x064 +#define OMAP35XX_GPIO_CLEARIRQENABLE2 0x070 +#define OMAP35XX_GPIO_SETIRQENABLE2 0x074 +#define OMAP35XX_GPIO_CLEARWKUENA 0x080 +#define OMAP35XX_GPIO_SETWKUENA 0x084 +#define OMAP35XX_GPIO_CLEARDATAOUT 0x090 +#define OMAP35XX_GPIO_SETDATAOUT 0x094 + + +/* + * MMC/SD/SDIO + */ + +/* Base addresses for the MMC/SD/SDIO modules */ +#define OMAP35XX_MMCHS1_HWBASE (OMAP35XX_L4_CORE_HWBASE + 0x0009C000) +#define OMAP35XX_MMCHS1_VBASE (OMAP35XX_L4_CORE_VBASE + 0x0009C000) +#define OMAP35XX_MMCHS2_HWBASE (OMAP35XX_L4_CORE_HWBASE + 0x000B4000) +#define OMAP35XX_MMCHS2_VBASE (OMAP35XX_L4_CORE_VBASE + 0x000B4000) +#define OMAP35XX_MMCHS3_HWBASE (OMAP35XX_L4_CORE_HWBASE + 0x000AD000) +#define OMAP35XX_MMCHS3_VBASE (OMAP35XX_L4_CORE_VBASE + 0x000AD000) +#define OMAP35XX_MMCHS_SIZE 0x00000200UL + +/* Register offsets within each of the MMC/SD/SDIO controllers */ +#define OMAP35XX_MMCHS_SYSCONFIG 0x010 +#define OMAP35XX_MMCHS_SYSSTATUS 0x014 +#define OMAP35XX_MMCHS_CSRE 0x024 +#define OMAP35XX_MMCHS_SYSTEST 0x028 +#define OMAP35XX_MMCHS_CON 0x02C +#define OMAP35XX_MMCHS_PWCNT 0x030 +#define OMAP35XX_MMCHS_BLK 0x104 +#define OMAP35XX_MMCHS_ARG 0x108 +#define OMAP35XX_MMCHS_CMD 0x10C +#define OMAP35XX_MMCHS_RSP10 0x110 +#define OMAP35XX_MMCHS_RSP32 0x114 +#define OMAP35XX_MMCHS_RSP54 0x118 +#define OMAP35XX_MMCHS_RSP76 0x11C +#define OMAP35XX_MMCHS_DATA 0x120 +#define OMAP35XX_MMCHS_PSTATE 0x124 +#define OMAP35XX_MMCHS_HCTL 0x128 +#define OMAP35XX_MMCHS_SYSCTL 0x12C +#define OMAP35XX_MMCHS_STAT 0x130 +#define OMAP35XX_MMCHS_IE 0x134 +#define OMAP35XX_MMCHS_ISE 0x138 +#define OMAP35XX_MMCHS_AC12 0x13C +#define OMAP35XX_MMCHS_CAPA 0x140 +#define OMAP35XX_MMCHS_CUR_CAPA 0x148 +#define OMAP35XX_MMCHS_REV 0x1FC + + + +#endif /* _ARM_OMAP3_REG_H_ */ Index: sys/arm/cortexa8/omap3/uart_bus_omap3.c =================================================================== --- sys/arm/cortexa8/omap3/uart_bus_omap3.c (revision 0) +++ sys/arm/cortexa8/omap3/uart_bus_omap3.c (revision 0) @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2010 + * Ben Gray . + * All rights reserved. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Ben Gray. + * 4. The name of the company nor the name of the author may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY BEN GRAY ``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 BEN GRAY 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include + +#include "uart_if.h" + +static int uart_omap3_probe(device_t dev); + + +/* --------------------------------------------------------------- */ +/* uart_omap3_methods + * + * Methods implemented for the UART device, note the only unique one + * is the 'probe', the others are done by the default 8250 UART + * driver. + */ +static device_method_t uart_omap3_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, uart_omap3_probe), + DEVMETHOD(device_attach, uart_bus_attach), + DEVMETHOD(device_detach, uart_bus_detach), + { 0, 0 } +}; + + +/* --------------------------------------------------------------- */ +/* uart_omap3_driver + * + * The driver device, which is just a standard 8250 type device. + * + */ +static driver_t uart_omap3_driver = { + uart_driver_name, + uart_omap3_methods, + sizeof(struct uart_softc), +}; + +extern SLIST_HEAD(uart_devinfo_list, uart_devinfo) uart_sysdevs; + +/* --------------------------------------------------------------- */ +/* + * uart_omap3_probe + * + * Called to check for the presence of the serial port and also + * performs initialisation of the UART device. + * + */ +static int uart_omap3_probe(device_t dev) +{ + struct uart_softc *sc; + int unit = device_get_unit(dev); + u_int rclk; + + sc = device_get_softc(dev); + sc->sc_class = &uart_ns8250_class; + //if (resource_int_value("uart", unit, "rclk", &rclk)) + rclk = OMAP35XX_UART_FREQ; + +printf("unit = %d\n", unit); + if (unit == 0) { + sc->sc_sysdev = SLIST_FIRST(&uart_sysdevs); + bcopy(&sc->sc_sysdev->bas, &sc->sc_bas, sizeof(sc->sc_bas)); + } + + if (bootverbose) + device_printf(dev, "rclk %u\n", rclk); + + return uart_bus_probe(dev, 2, rclk, 0, 0); +} + +DRIVER_MODULE(uart, omap3, uart_omap3_driver, uart_devclass, 0, 0); + Index: sys/arm/cortexa8/omap3/omap3_scm.h =================================================================== --- sys/arm/cortexa8/omap3/omap3_scm.h (revision 0) +++ sys/arm/cortexa8/omap3/omap3_scm.h (revision 0) @@ -0,0 +1,620 @@ +/* + * Copyright (c) 2010 + * Ben Gray . + * All rights reserved. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Ben Gray. + * 4. The name of the company nor the name of the author may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY BEN GRAY ``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 BEN GRAY 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. + */ + + +/** + * Functions to configure the PIN multiplexing on the chip. + * + * This is different from the GPIO module in that it is used to configure the + * pins between modules not just GPIO input output. + * + */ +#ifndef _OMAP3_PINMUX_H_ +#define _OMAP3_PINMUX_H_ + + + +#define CONTROL_PADCONF_WAKEUP_EVENT (1UL << 15) +#define CONTROL_PADCONF_WAKEUP_ENABLE (1UL << 14) +#define CONTROL_PADCONF_OFF_PULL_UP (1UL << 13) +#define CONTROL_PADCONF_OFF_PULL_ENABLE (1UL << 12) +#define CONTROL_PADCONF_OFF_OUT_HIGH (1UL << 11) +#define CONTROL_PADCONF_OFF_OUT_ENABLE (1UL << 10) +#define CONTROL_PADCONF_OFF_ENABLE (1UL << 9) +#define CONTROL_PADCONF_INPUT_ENABLE (1UL << 8) +#define CONTROL_PADCONF_PULL_UP (1UL << 4) +#define CONTROL_PADCONF_PULL_ENABLE (1UL << 3) +#define CONTROL_PADCONF_MUXMODE_MASK (0x7) + + + +/* Active pin states */ +#define PADCONF_PIN_OUTPUT 0 +#define PADCONF_PIN_INPUT CONTROL_PADCONF_INPUT_ENABLE +#define PADCONF_PIN_INPUT_PULLUP ( CONTROL_PADCONF_INPUT_ENABLE \ + | CONTROL_PADCONF_PULL_ENABLE \ + | CONTROL_PADCONF_PULL_UP) +#define PADCONF_PIN_INPUT_PULLDOWN ( CONTROL_PADCONF_INPUT_ENABLE \ + | CONTROL_PADCONF_PULL_ENABLE ) + +/* Off mode states */ +#define PADCONF_PIN_OFF_NONE 0 +#define PADCONF_PIN_OFF_OUTPUT_HIGH ( CONTROL_PADCONF_OFF_ENABLE \ + | CONTROL_PADCONF_OFF_OUT_ENABLE \ + | CONTROL_PADCONF_OFF_OUT_HIGH) +#define PADCONF_PIN_OFF_OUTPUT_LOW ( CONTROL_PADCONF_OFF_ENABLE \ + | CONTROL_PADCONF_OFF_OUT_ENABLE) +#define PADCONF_PIN_OFF_INPUT_PULLUP ( CONTROL_PADCONF_OFF_ENABLE \ + | CONTROL_PADCONF_OFF_PULL_ENABLE \ + | CONTROL_PADCONF_OFF_PULL_UP) +#define PADCONF_PIN_OFF_INPUT_PULLDOWN ( CONTROL_PADCONF_OFF_ENABLE \ + | CONTROL_PADCONF_OFF_PULL_ENABLE) +#define PADCONF_PIN_OFF_WAKEUPENABLE CONTROL_PADCONF_WAKEUP_ENABLE + + + +/* + * bits 7:0 - mode + * bits 31:16 - register offset + * + */ +#if 0 + +#define _PINMUX_PIN(off, mode) (((off) << 16) | ((mode) & 0x7)) +#define _PINMUX_PIN_MODE(pin) (((pin) >> 16) & 0xFFFF) +#define _PINMUX_PIN_OFFSET(pin) ((pin) & 0x7) + +#define _PINMUX_PIN_DEF(name, off, mode) \ + name = _PINMUX_PIN(off, mode) + +#define _MERGE(a,b) a ## b +#define _MERGE2(a,b) _MERGE(a,b) + +#define _NA _MERGE2(pinumx_reserved_,__COUNTER__) + +#define _PINMUX_PIN_DEFEX(off, m0, m1, m2, m3, m4, m5, m6, m7) \ + m0 = _PINMUX_PIN(off, 0), \ + m1 = _PINMUX_PIN(off, 1), \ + m2 = _PINMUX_PIN(off, 2), \ + m3 = _PINMUX_PIN(off, 3), \ + m4 = _PINMUX_PIN(off, 4), \ + m5 = _PINMUX_PIN(off, 5), \ + m6 = _PINMUX_PIN(off, 6), \ + m7 = _PINMUX_PIN(off, 7) + + +enum pinumx_pin { + _PINMUX_PIN_DEF(gpmc_a1, 0x007A, 0), _PINMUX_PIN_DEF(gpio_34, 0x007A, 4), + _PINMUX_PIN_DEF(gpmc_a2, 0x007C, 0), _PINMUX_PIN_DEF(gpio_35, 0x007C, 4), + _PINMUX_PIN_DEF(gpmc_a3, 0x007E, 0), _PINMUX_PIN_DEF(gpio_36, 0x007E, 4), + _PINMUX_PIN_DEF(gpmc_a4, 0x0080, 0), _PINMUX_PIN_DEF(gpio_37, 0x0080, 4), + _PINMUX_PIN_DEF(gpmc_a5, 0x0082, 0), _PINMUX_PIN_DEF(gpio_38, 0x0082, 4), + _PINMUX_PIN_DEF(gpmc_a6, 0x0084, 0), _PINMUX_PIN_DEF(gpio_39, 0x0084, 4), + _PINMUX_PIN_DEF(gpmc_a7, 0x0086, 0), _PINMUX_PIN_DEF(gpio_40, 0x0086, 4), + _PINMUX_PIN_DEF(gpmc_a8, 0x0088, 0), _PINMUX_PIN_DEF(gpio_41, 0x0088, 4), + _PINMUX_PIN_DEF(gpmc_a9, 0x008A, 0), _PINMUX_PIN_DEF(gpio_42, 0x008A, 4), + _PINMUX_PIN_DEF(gpmc_a10,0x008C, 0), _PINMUX_PIN_DEF(gpio_43, 0x008C, 4), + + _PINMUX_PIN_DEF(gpmc_d0, 0x008E, 0), + _PINMUX_PIN_DEF(gpmc_d1, 0x0090, 0), + _PINMUX_PIN_DEF(gpmc_d2, 0x0092, 0), + _PINMUX_PIN_DEF(gpmc_d3, 0x0094, 0), + _PINMUX_PIN_DEF(gpmc_d4, 0x0096, 0), + _PINMUX_PIN_DEF(gpmc_d5, 0x0098, 0), + _PINMUX_PIN_DEF(gpmc_d6, 0x009A, 0), + _PINMUX_PIN_DEF(gpmc_d7, 0x009C, 0), + _PINMUX_PIN_DEF(gpmc_d8, 0x009E, 0), _PINMUX_PIN_DEF(gpio_44, 0x009E, 4), + _PINMUX_PIN_DEF(gpmc_d9, 0x00A0, 0), _PINMUX_PIN_DEF(gpio_45, 0x00A0, 4), + _PINMUX_PIN_DEF(gpmc_d10,0x00A2, 0), _PINMUX_PIN_DEF(gpio_46, 0x00A2, 4), + _PINMUX_PIN_DEF(gpmc_d11,0x00A4, 0), _PINMUX_PIN_DEF(gpio_47, 0x00A4, 4), + _PINMUX_PIN_DEF(gpmc_d12,0x00A6, 0), _PINMUX_PIN_DEF(gpio_48, 0x00A6, 4), + _PINMUX_PIN_DEF(gpmc_d13,0x00A8, 0), _PINMUX_PIN_DEF(gpio_49, 0x00A8, 4), + _PINMUX_PIN_DEF(gpmc_d14,0x00AA, 0), _PINMUX_PIN_DEF(gpio_50, 0x00AA, 4), + _PINMUX_PIN_DEF(gpmc_d15,0x00AC, 0), _PINMUX_PIN_DEF(gpio_51, 0x00AC, 4), + + _PINMUX_PIN_DEF(gpmc_ncs0, 0x00AE, 0), + _PINMUX_PIN_DEF(gpmc_ncs1, 0x00B0, 0), _PINMUX_PIN_DEF(gpio_52, 0x00B0, 4), + _PINMUX_PIN_DEF(gpmc_ncs2, 0x00B2, 0), _PINMUX_PIN_DEF(gpio_53, 0x00B2, 4), + _PINMUX_PIN_DEF(gpmc_ncs3, 0x00B4, 0), _PINMUX_PIN_DEF(gpio_54, 0x00B4, 4), + _PINMUX_PIN_DEF(gpmc_ncs4, 0x00B6, 0), + _PINMUX_PIN_DEF(mcbsp4_clkx, 0x00B6, 2), + _PINMUX_PIN_DEF(gpt9_pwm_evt, 0x00B6, 3), + _PINMUX_PIN_DEF(gpio_55, 0x00B6, 4), + _PINMUX_PIN_DEF(gpmc_ncs5, 0x00B8, 0), + _PINMUX_PIN_DEF(mcbsp4_dr, 0x00B8, 2), + _PINMUX_PIN_DEF(gpt10_pwm_evt, 0x00B8, 3), + _PINMUX_PIN_DEF(gpio_56, 0x00B8, 4), + _PINMUX_PIN_DEF(gpmc_ncs6, 0x00BA, 0), + _PINMUX_PIN_DEF(mcbsp4_dx, 0x00BA, 2), + _PINMUX_PIN_DEF(gpt11_pwm_evt, 0x00BA, 3), + _PINMUX_PIN_DEF(gpio_57, 0x00BA, 4), + _PINMUX_PIN_DEF(gpmc_ncs7, 0x00BC, 0), + _PINMUX_PIN_DEF(gpmc_io_dir, 0x00BC, 1), + _PINMUX_PIN_DEF(mcbsp4_fsx, 0x00BC, 2), + _PINMUX_PIN_DEF(gpt18_pwm_evt, 0x00BC, 3), + _PINMUX_PIN_DEF(gpio_58, 0x00BC, 4), + _PINMUX_PIN_DEF(gpmc_clk, 0x00BE, 0), + _PINMUX_PIN_DEF(gpio_59, 0x00BE, 4), + _PINMUX_PIN_DEF(gpmc_nbe0_cle, 0x00C6, 0), _PINMUX_PIN_DEF(gpio_60, 0x00C6, 4), + _PINMUX_PIN_DEF(gpmc_nbe1, 0x00C8, 0), _PINMUX_PIN_DEF(gpio_61, 0x00C8, 4), + _PINMUX_PIN_DEF(gpmc_nwp, 0x00CA, 0), _PINMUX_PIN_DEF(gpio_62, 0x00CA, 4), + _PINMUX_PIN_DEF(gpmc_wait1, 0x00CE, 0), _PINMUX_PIN_DEF(gpio_63, 0x00CE, 4), + _PINMUX_PIN_DEF(gpmc_wait2, 0x00D0, 0), _PINMUX_PIN_DEF(gpio_64, 0x00D0, 4), + _PINMUX_PIN_DEF(gpmc_wait3, 0x00D2, 0), _PINMUX_PIN_DEF(gpio_65, 0x00D2, 4), + + + + /* MMC Pin multiplexing */ + _PINMUX_PIN_DEF(mmc1_clk, 0x0144, 0), + _PINMUX_PIN_DEF(ms_clk, 0x0144, 1), + _PINMUX_PIN_DEF(gpio_120, 0x0144, 4), + _PINMUX_PIN_DEF(mmc1_cmd, 0x0146, 0), + _PINMUX_PIN_DEF(ms_bs, 0x0146, 1), + _PINMUX_PIN_DEF(gpio_121, 0x0146, 4), + _PINMUX_PIN_DEF(mmc1_dat0, 0x0148, 0), + _PINMUX_PIN_DEF(ms_dat0, 0x0148, 1), + _PINMUX_PIN_DEF(gpio_122, 0x0148, 4), + _PINMUX_PIN_DEF(mmc1_dat1, 0x014A, 0), + _PINMUX_PIN_DEF(ms_dat1, 0x014A, 1), + _PINMUX_PIN_DEF(gpio_123, 0x014A, 4), + _PINMUX_PIN_DEF(mmc1_dat2, 0x014C, 0), + _PINMUX_PIN_DEF(ms_dat2, 0x014C, 1), + _PINMUX_PIN_DEF(gpio_124, 0x014C, 4), + _PINMUX_PIN_DEF(mmc1_dat3, 0x014E, 0), + _PINMUX_PIN_DEF(ms_dat3, 0x014E, 1), + _PINMUX_PIN_DEF(gpio_125, 0x014E, 4), + _PINMUX_PIN_DEF(mmc1_dat4, 0x0150, 0), + _PINMUX_PIN_DEF(sim_io, 0x0150, 2), + _PINMUX_PIN_DEF(gpio_126, 0x0150, 4), + _PINMUX_PIN_DEF(mmc1_dat5, 0x0152, 0), + _PINMUX_PIN_DEF(sim_clk, 0x0152, 2), + _PINMUX_PIN_DEF(gpio_127, 0x0152, 4), + _PINMUX_PIN_DEF(mmc1_dat6, 0x0154, 0), + _PINMUX_PIN_DEF(sim_pwrctrl, 0x0154, 2), + _PINMUX_PIN_DEF(gpio_128, 0x0154, 4), + _PINMUX_PIN_DEF(mmc1_dat7, 0x0156, 0), + _PINMUX_PIN_DEF(sim_rst, 0x0156, 2), + _PINMUX_PIN_DEF(gpio_129, 0x0156, 4), + + _PINMUX_PIN_DEF(mmc2_clk, 0x0158, 0), + _PINMUX_PIN_DEF(mcspi3_clk, 0x0158, 1), + _PINMUX_PIN_DEF(gpio_130, 0x0158, 4), + _PINMUX_PIN_DEF(mmc2_cmd, 0x015A, 0), + _PINMUX_PIN_DEF(mcspi3_simo, 0x015A, 1), + _PINMUX_PIN_DEF(gpio_131, 0x015A, 4), + _PINMUX_PIN_DEF(mmc2_dat0, 0x015C, 0), + _PINMUX_PIN_DEF(mcspi3_somi, 0x015C, 1), + _PINMUX_PIN_DEF(gpio_132, 0x015C, 4), + _PINMUX_PIN_DEF(mmc2_dat1, 0x015E, 0), + _PINMUX_PIN_DEF(gpio_133, 0x015E, 4), + _PINMUX_PIN_DEF(mmc2_dat2, 0x0160, 0), + _PINMUX_PIN_DEF(gpio_134, 0x0160, 4), + _PINMUX_PIN_DEF(mmc2_dat3, 0x0162, 0), + _PINMUX_PIN_DEF(mcspi3_cs0, 0x0162, 1), + _PINMUX_PIN_DEF(gpio_135, 0x0162, 4), + _PINMUX_PIN_DEF(mmc2_dat4, 0x0164, 0), + _PINMUX_PIN_DEF(mmc2_dir_dat0, 0x0164, 1), + _PINMUX_PIN_DEF(mmc3_dat0, 0x0164, 3), + _PINMUX_PIN_DEF(gpio_136, 0x0164, 4), + _PINMUX_PIN_DEF(mmc2_dat5, 0x0166, 0), + _PINMUX_PIN_DEF(mmc2_dir_dat1, 0x0166, 1), + _PINMUX_PIN_DEF(cam_global_reset, 0x0166, 2), + _PINMUX_PIN_DEF(mmc3_dat1, 0x0166, 3), + _PINMUX_PIN_DEF(gpio_137, 0x0166, 4), + _PINMUX_PIN_DEF(hsusb3_tll_stp, 0x0166, 5), + _PINMUX_PIN_DEF(mm3_rxdp, 0x0166, 6), + + _PINMUX_PIN_DEFEX(0x0168, mmc2_dat6, mmc2_dir_cmd, cam_shutter, mmc3_dat2, gpio_138, hsusb3_tll_dir, _NA, _NA), + _PINMUX_PIN_DEFEX(0x016A, mmc2_dat7, mmc2_clkin, _NA, mmc3_dat3, gpio_139, hsusb3_tll_nxt, mm3_rxdm, _NA), + _PINMUX_PIN_DEFEX(0x016C, mcbsp3_dx, uart2_cts, _NA, _NA, gpio_140, hsusb3_tll_data4, _NA, _NA), + _PINMUX_PIN_DEFEX(0x016E, mcbsp3_dr, uart2_rts, _NA, _NA, gpio_141, hsusb3_tll_data5, _NA, _NA), + _PINMUX_PIN_DEFEX(0x0170, mcbsp3_clkx, uart2_tx, _NA, _NA, gpio_142, hsusb3_tll_data6, _NA, _NA), + _PINMUX_PIN_DEFEX(0x0172, mcbsp3_fsx, uart2_rx, _NA, _NA, gpio_143, hsusb3_tll_data7, _NA, _NA), + _PINMUX_PIN_DEFEX(0x0174, uart2_cts, mcbsp3_dx, gpt9_pwm_evt, _NA, gpio_144, _NA, _NA, _NA), + _PINMUX_PIN_DEFEX(0x0176, uart2_rts, mcbsp3_dr, gpt10_pwm_evt, _NA, gpio_145, _NA, _NA, _NA), + _PINMUX_PIN_DEFEX(0x0178, uart2_tx, mcbsp3_clkx, gpt11_pwm_evt, _NA, gpio_146, _NA, _NA, _NA), + _PINMUX_PIN_DEFEX(0x017A, uart2_rx, mcbsp3_fsx, gpt12_pwm_evt, _NA, gpio_147, _NA, _NA, _NA), + _PINMUX_PIN_DEFEX(0x017C, uart1_tx, _NA, _NA, _NA, gpio_148, _NA, _NA, _NA), + _PINMUX_PIN_DEFEX(0x017E, uart1_rts, _NA, _NA, _NA, gpio_149, _NA, _NA, _NA), + _PINMUX_PIN_DEFEX(0x0180, uart1_cts, _NA, _NA, _NA, gpio_150, hsusb3_tll_clk, _NA, _NA), + _PINMUX_PIN_DEFEX(0x0182, uart1_rx, _NA, mcbsp1_clkr, mcspi4_clk, gpio_151, _NA, _NA, _NA), + _PINMUX_PIN_DEFEX(0x0184, mcbsp4_clkx, _NA, _NA, _NA, gpio_152, hsusb3_tll_data1, mm3_txse0, _NA), + _PINMUX_PIN_DEFEX(0x0186, mcbsp4_dr, _NA, _NA, _NA, gpio_153, hsusb3_tll_data0, mm3_rxrcv, _NA), + _PINMUX_PIN_DEFEX(0x0188, mcbsp4_dx, _NA, _NA, _NA, gpio_154, hsusb3_tll_data2, mm3_txdat, _NA), + _PINMUX_PIN_DEFEX(0x018A, mcbsp4_fsx, _NA, _NA, _NA, gpio_155, hsusb3_tll_data3, mm3_txen_n, _NA), + _PINMUX_PIN_DEFEX(0x018C, mcbsp1_clkr, mcspi4_clk, sim_cd, _NA, gpio_156, _NA, _NA, _NA), + _PINMUX_PIN_DEFEX(0x018E, mcbsp1_fsr, _NA, cam_global_res, _NA, gpio_157, _NA, _NA, _NA), + _PINMUX_PIN_DEFEX(0x0190, mcbsp1_dx, mcspi4_simo, mcbsp3_dx, _NA, gpio_158, _NA, _NA, _NA), + _PINMUX_PIN_DEFEX(0x0192, mcbsp1_dr, mcspi4_somi, mcbsp3_dr, _NA, gpio_159, _NA, _NA, _NA), + _PINMUX_PIN_DEFEX(0x0194, mcbsp_clks, cam_shutter, _NA, _NA, gpio_160, uart1_cts, _NA, _NA), + _PINMUX_PIN_DEFEX(0x0196, mcbsp1_fsx, mcspi4_cs0, mcbsp3_fsx, _NA, gpio_161, _NA, _NA, _NA), + _PINMUX_PIN_DEFEX(0x0198, mcbsp1_clkx, mcbsp3_clkx, _NA, _NA, gpio_162, _NA, _NA, _NA), +}; + +#endif + +#define CONTROL_PADCONF_SDRC_D0 0x0030 +#define CONTROL_PADCONF_SDRC_D1 0x0032 +#define CONTROL_PADCONF_SDRC_D2 0x0034 +#define CONTROL_PADCONF_SDRC_D3 0x0036 +#define CONTROL_PADCONF_SDRC_D4 0x0038 +#define CONTROL_PADCONF_SDRC_D5 0x003A +#define CONTROL_PADCONF_SDRC_D6 0x003C +#define CONTROL_PADCONF_SDRC_D7 0x003E +#define CONTROL_PADCONF_SDRC_D8 0x0040 +#define CONTROL_PADCONF_SDRC_D9 0x0042 +#define CONTROL_PADCONF_SDRC_D10 0x0044 +#define CONTROL_PADCONF_SDRC_D11 0x0046 +#define CONTROL_PADCONF_SDRC_D12 0x0048 +#define CONTROL_PADCONF_SDRC_D13 0x004A +#define CONTROL_PADCONF_SDRC_D14 0x004C +#define CONTROL_PADCONF_SDRC_D15 0x004E +#define CONTROL_PADCONF_SDRC_D16 0x0050 +#define CONTROL_PADCONF_SDRC_D17 0x0052 +#define CONTROL_PADCONF_SDRC_D18 0x0054 +#define CONTROL_PADCONF_SDRC_D19 0x0056 +#define CONTROL_PADCONF_SDRC_D20 0x0058 +#define CONTROL_PADCONF_SDRC_D21 0x005A +#define CONTROL_PADCONF_SDRC_D22 0x005C +#define CONTROL_PADCONF_SDRC_D23 0x005E +#define CONTROL_PADCONF_SDRC_D24 0x0060 +#define CONTROL_PADCONF_SDRC_D25 0x0062 +#define CONTROL_PADCONF_SDRC_D26 0x0064 +#define CONTROL_PADCONF_SDRC_D27 0x0066 +#define CONTROL_PADCONF_SDRC_D28 0x0068 +#define CONTROL_PADCONF_SDRC_D29 0x006A +#define CONTROL_PADCONF_SDRC_D30 0x006C +#define CONTROL_PADCONF_SDRC_D31 0x006E +#define CONTROL_PADCONF_SDRC_CLK 0x0070 +#define CONTROL_PADCONF_SDRC_DQS0 0x0072 +#define CONTROL_PADCONF_SDRC_CKE0 0x0262 +#define CONTROL_PADCONF_SDRC_CKE1 0x0264 +#define CONTROL_PADCONF_SDRC_DQS1 0x0074 +#define CONTROL_PADCONF_SDRC_DQS2 0x0076 +#define CONTROL_PADCONF_SDRC_DQS3 0x0078 + +#define CONTROL_PADCONF_GPMC_A1 0x007A +#define CONTROL_PADCONF_GPMC_A2 0x007C +#define CONTROL_PADCONF_GPMC_A3 0x007E +#define CONTROL_PADCONF_GPMC_A4 0x0080 +#define CONTROL_PADCONF_GPMC_A5 0x0082 +#define CONTROL_PADCONF_GPMC_A6 0x0084 +#define CONTROL_PADCONF_GPMC_A7 0x0086 +#define CONTROL_PADCONF_GPMC_A8 0x0088 +#define CONTROL_PADCONF_GPMC_A9 0x008A +#define CONTROL_PADCONF_GPMC_A10 0x008C +#define CONTROL_PADCONF_GPMC_A11 0x008E +#define CONTROL_PADCONF_GPMC_D1 0x0090 +#define CONTROL_PADCONF_GPMC_D2 0x0092 +#define CONTROL_PADCONF_GPMC_D3 0x0094 +#define CONTROL_PADCONF_GPMC_D4 0x0096 +#define CONTROL_PADCONF_GPMC_D5 0x0098 +#define CONTROL_PADCONF_GPMC_D6 0x009A +#define CONTROL_PADCONF_GPMC_D7 0x009C +#define CONTROL_PADCONF_GPMC_D8 0x009E +#define CONTROL_PADCONF_GPMC_D9 0x00A0 +#define CONTROL_PADCONF_GPMC_D10 0x00A2 +#define CONTROL_PADCONF_GPMC_D11 0x00A4 +#define CONTROL_PADCONF_GPMC_D12 0x00A6 +#define CONTROL_PADCONF_GPMC_D13 0x00A8 +#define CONTROL_PADCONF_GPMC_D14 0x00AA +#define CONTROL_PADCONF_GPMC_D15 0x00AC +#define CONTROL_PADCONF_GPMC_NCS0 0x00AE +#define CONTROL_PADCONF_GPMC_NCS1 0x00B0 +#define CONTROL_PADCONF_GPMC_NCS2 0x00B2 +#define CONTROL_PADCONF_GPMC_NCS3 0x00B4 +#define CONTROL_PADCONF_GPMC_NCS4 0x00B6 +#define CONTROL_PADCONF_GPMC_NCS5 0x00B8 +#define CONTROL_PADCONF_GPMC_NCS6 0x00BA +#define CONTROL_PADCONF_GPMC_NCS7 0x00BC +#define CONTROL_PADCONF_GPMC_CLK 0x00BE +#define CONTROL_PADCONF_GPMC_NADV_ALE 0x00C0 +#define CONTROL_PADCONF_GPMC_NOE 0x00C2 +#define CONTROL_PADCONF_GPMC_NWE 0x00C4 +#define CONTROL_PADCONF_GPMC_NBE0_CLE 0x00C6 +#define CONTROL_PADCONF_GPMC_NBE1 0x00C8 +#define CONTROL_PADCONF_GPMC_NWP 0x00CA +#define CONTROL_PADCONF_GPMC_WAIT0 0x00CC +#define CONTROL_PADCONF_GPMC_WAIT1 0x00CE +#define CONTROL_PADCONF_GPMC_WAIT2 0x00D0 +#define CONTROL_PADCONF_GPMC_WAIT3 0x00D2 + +#define CONTROL_PADCONF_DSS_PCLK 0x00D4 +#define CONTROL_PADCONF_DSS_HSYNC 0x00D6 +#define CONTROL_PADCONF_DSS_VSYNC 0x00D8 +#define CONTROL_PADCONF_DSS_ACBIAS 0x00DA +#define CONTROL_PADCONF_DSS_DATA0 0x00DC +#define CONTROL_PADCONF_DSS_DATA1 0x00DE +#define CONTROL_PADCONF_DSS_DATA2 0x00E0 +#define CONTROL_PADCONF_DSS_DATA3 0x00E2 +#define CONTROL_PADCONF_DSS_DATA4 0x00E4 +#define CONTROL_PADCONF_DSS_DATA5 0x00E6 +#define CONTROL_PADCONF_DSS_DATA6 0x00E8 +#define CONTROL_PADCONF_DSS_DATA7 0x00EA +#define CONTROL_PADCONF_DSS_DATA8 0x00EC +#define CONTROL_PADCONF_DSS_DATA9 0x00EE +#define CONTROL_PADCONF_DSS_DATA10 0x00F0 +#define CONTROL_PADCONF_DSS_DATA11 0x00F2 +#define CONTROL_PADCONF_DSS_DATA12 0x00F4 +#define CONTROL_PADCONF_DSS_DATA13 0x00F6 +#define CONTROL_PADCONF_DSS_DATA14 0x00F8 +#define CONTROL_PADCONF_DSS_DATA15 0x00FA +#define CONTROL_PADCONF_DSS_DATA16 0x00FC +#define CONTROL_PADCONF_DSS_DATA17 0x00FE +#define CONTROL_PADCONF_DSS_DATA18 0x0100 +#define CONTROL_PADCONF_DSS_DATA19 0x0102 +#define CONTROL_PADCONF_DSS_DATA20 0x0104 +#define CONTROL_PADCONF_DSS_DATA21 0x0106 +#define CONTROL_PADCONF_DSS_DATA22 0x0108 +#define CONTROL_PADCONF_DSS_DATA23 0x010A + +#define CONTROL_PADCONF_CAM_HS 0x010C +#define CONTROL_PADCONF_CAM_VS 0x010E +#define CONTROL_PADCONF_CAM_XCLKA 0x0110 +#define CONTROL_PADCONF_CAM_PCLK 0x0112 +#define CONTROL_PADCONF_CAM_FLD 0x0114 +#define CONTROL_PADCONF_CAM_D0 0x0116 +#define CONTROL_PADCONF_CAM_D1 0x0118 +#define CONTROL_PADCONF_CAM_D2 0x011A +#define CONTROL_PADCONF_CAM_D3 0x011C +#define CONTROL_PADCONF_CAM_D4 0x011E +#define CONTROL_PADCONF_CAM_D5 0x0120 +#define CONTROL_PADCONF_CAM_D6 0x0122 +#define CONTROL_PADCONF_CAM_D7 0x0124 +#define CONTROL_PADCONF_CAM_D8 0x0126 +#define CONTROL_PADCONF_CAM_D9 0x0128 +#define CONTROL_PADCONF_CAM_D10 0x012A +#define CONTROL_PADCONF_CAM_D11 0x012C +#define CONTROL_PADCONF_CAM_XCLKB 0x012E +#define CONTROL_PADCONF_CAM_WEN 0x0130 +#define CONTROL_PADCONF_CAM_STROBE 0x0132 + +#define CONTROL_PADCONF_CSI2_DX0 0x0134 +#define CONTROL_PADCONF_CSI2_DY0 0x0136 +#define CONTROL_PADCONF_CSI2_DX1 0x0138 +#define CONTROL_PADCONF_CSI2_DY1 0x013A + +#define CONTROL_PADCONF_MMC1_CLK 0x0144 +#define CONTROL_PADCONF_MMC1_CMD 0x0146 +#define CONTROL_PADCONF_MMC1_DAT0 0x0148 +#define CONTROL_PADCONF_MMC1_DAT1 0x014A +#define CONTROL_PADCONF_MMC1_DAT2 0x014C +#define CONTROL_PADCONF_MMC1_DAT3 0x014E +#define CONTROL_PADCONF_MMC1_DAT4 0x0150 +#define CONTROL_PADCONF_MMC1_DAT5 0x0152 +#define CONTROL_PADCONF_MMC1_DAT6 0x0154 +#define CONTROL_PADCONF_MMC1_DAT7 0x0156 + +#define CONTROL_PADCONF_MMC2_CLK 0x0158 +#define CONTROL_PADCONF_MMC2_CMD 0x015A +#define CONTROL_PADCONF_MMC2_DAT0 0x015C +#define CONTROL_PADCONF_MMC2_DAT1 0x015C +#define CONTROL_PADCONF_MMC2_DAT2 0x0160 +#define CONTROL_PADCONF_MMC2_DAT3 0x0160 +#define CONTROL_PADCONF_MMC2_DAT4 0x0164 +#define CONTROL_PADCONF_MMC2_DAT5 0x0164 +#define CONTROL_PADCONF_MMC2_DAT6 0x0168 +#define CONTROL_PADCONF_MMC2_DAT7 0x0168 + +#define CONTROL_PADCONF_UART1_TX 0x017C +#define CONTROL_PADCONF_UART1_RTS 0x017E +#define CONTROL_PADCONF_UART1_CTS 0x0180 +#define CONTROL_PADCONF_UART1_RX 0x0182 +#define CONTROL_PADCONF_UART2_CTS 0x0174 +#define CONTROL_PADCONF_UART2_RTS 0x0176 +#define CONTROL_PADCONF_UART2_TX 0x0178 +#define CONTROL_PADCONF_UART2_RX 0x017A +#define CONTROL_PADCONF_UART3_CTS_RCTX 0x019A +#define CONTROL_PADCONF_UART3_RTS_SD 0x019C +#define CONTROL_PADCONF_UART3_RX_IRRX 0x019E +#define CONTROL_PADCONF_UART3_TX_IRTX 0x01A0 + +#define CONTROL_PADCONF_MCBSP1_CLKR 0x018C +#define CONTROL_PADCONF_MCBSP1_FSR 0x018E +#define CONTROL_PADCONF_MCBSP1_DX 0x0190 +#define CONTROL_PADCONF_MCBSP1_DR 0x0192 +#define CONTROL_PADCONF_MCBSP_CLKS 0x0194 +#define CONTROL_PADCONF_MCBSP1_FSX 0x0196 +#define CONTROL_PADCONF_MCBSP1_CLKX 0x0198 +#define CONTROL_PADCONF_MCBSP2_FSX 0x013C +#define CONTROL_PADCONF_MCBSP2_CLKX 0x013E +#define CONTROL_PADCONF_MCBSP2_DR 0x0140 +#define CONTROL_PADCONF_MCBSP2_DX 0x0142 +#define CONTROL_PADCONF_MCBSP3_DX 0x016C +#define CONTROL_PADCONF_MCBSP3_DR 0x016E +#define CONTROL_PADCONF_MCBSP3_CLKX 0x0170 +#define CONTROL_PADCONF_MCBSP3_FSX 0x0172 +#define CONTROL_PADCONF_MCBSP4_CLKX 0x0184 +#define CONTROL_PADCONF_MCBSP4_DR 0x0186 +#define CONTROL_PADCONF_MCBSP4_DX 0x0188 +#define CONTROL_PADCONF_MCBSP4_FSX 0x018A + +#define CONTROL_PADCONF_HSUSB0_CLK 0x01A2 +#define CONTROL_PADCONF_HSUSB0_STP 0x01A4 +#define CONTROL_PADCONF_HSUSB0_DIR 0x01A6 +#define CONTROL_PADCONF_HSUSB0_NXT 0x01A8 +#define CONTROL_PADCONF_HSUSB0_DATA0 0x01AA +#define CONTROL_PADCONF_HSUSB0_DATA1 0x01AC +#define CONTROL_PADCONF_HSUSB0_DATA2 0x01AE +#define CONTROL_PADCONF_HSUSB0_DATA3 0x01B0 +#define CONTROL_PADCONF_HSUSB0_DATA4 0x01B2 +#define CONTROL_PADCONF_HSUSB0_DATA5 0x01B4 +#define CONTROL_PADCONF_HSUSB0_DATA6 0x01B6 +#define CONTROL_PADCONF_HSUSB0_DATA7 0x01B8 + +#define CONTROL_PADCONF_I2C1_SCL 0x01BA +#define CONTROL_PADCONF_I2C1_SDA 0x01BC +#define CONTROL_PADCONF_I2C2_SCL 0x01BE +#define CONTROL_PADCONF_I2C2_SDA 0x01C0 +#define CONTROL_PADCONF_I2C3_SCL 0x01C2 +#define CONTROL_PADCONF_I2C3_SDA 0x01C4 +#define CONTROL_PADCONF_I2C4_SCL 0x0A00 +#define CONTROL_PADCONF_I2C4_SDA 0x0A02 + +#define CONTROL_PADCONF_HDQ_SIO 0x01C6 +#define CONTROL_PADCONF_MCSPI1_CLK 0x01C8 +#define CONTROL_PADCONF_MCSPI1_SIMO 0x01CA +#define CONTROL_PADCONF_MCSPI1_SOMI 0x01CC +#define CONTROL_PADCONF_MCSPI1_CS0 0x01CE +#define CONTROL_PADCONF_MCSPI1_CS1 0x01D0 +#define CONTROL_PADCONF_MCSPI1_CS2 0x01D2 +#define CONTROL_PADCONF_MCSPI1_CS3 0x01D4 +#define CONTROL_PADCONF_MCSPI2_CLK 0x01D6 +#define CONTROL_PADCONF_MCSPI2_SIMO 0x01D8 +#define CONTROL_PADCONF_MCSPI2_SOMI 0x01DA +#define CONTROL_PADCONF_MCSPI2_CS0 0x01DC +#define CONTROL_PADCONF_MCSPI2_CS1 0x01DE + +#define CONTROL_PADCONF_ETK_CLK 0x05D8 +#define CONTROL_PADCONF_ETK_CTL 0x05DA +#define CONTROL_PADCONF_ETK_D0 0x05DC +#define CONTROL_PADCONF_ETK_D1 0x05DE +#define CONTROL_PADCONF_ETK_D2 0x05E0 +#define CONTROL_PADCONF_ETK_D3 0x05E2 +#define CONTROL_PADCONF_ETK_D4 0x05E4 +#define CONTROL_PADCONF_ETK_D5 0x05E6 +#define CONTROL_PADCONF_ETK_D6 0x05E8 +#define CONTROL_PADCONF_ETK_D7 0x05EA +#define CONTROL_PADCONF_ETK_D8 0x05EC +#define CONTROL_PADCONF_ETK_D9 0x05EE +#define CONTROL_PADCONF_ETK_D10 0x05F0 +#define CONTROL_PADCONF_ETK_D11 0x05F2 +#define CONTROL_PADCONF_ETK_D12 0x05F4 +#define CONTROL_PADCONF_ETK_D13 0x05F6 +#define CONTROL_PADCONF_ETK_D14 0x05F8 +#define CONTROL_PADCONF_ETK_D15 0x05FA + +#define CONTROL_PADCONF_SAD2D_MCAD0 0x01E4 +#define CONTROL_PADCONF_SAD2D_MCAD1 0x01E6 +#define CONTROL_PADCONF_SAD2D_MCAD2 0x01E8 +#define CONTROL_PADCONF_SAD2D_MCAD3 0x01EA +#define CONTROL_PADCONF_SAD2D_MCAD4 0x01EC +#define CONTROL_PADCONF_SAD2D_MCAD5 0x01EE +#define CONTROL_PADCONF_SAD2D_MCAD6 0x01F0 +#define CONTROL_PADCONF_SAD2D_MCAD7 0x01F2 +#define CONTROL_PADCONF_SAD2D_MCAD8 0x01F4 +#define CONTROL_PADCONF_SAD2D_MCAD9 0x01F6 +#define CONTROL_PADCONF_SAD2D_MCAD10 0x01F8 +#define CONTROL_PADCONF_SAD2D_MCAD11 0x01FA +#define CONTROL_PADCONF_SAD2D_MCAD12 0x01FC +#define CONTROL_PADCONF_SAD2D_MCAD13 0x01FE +#define CONTROL_PADCONF_SAD2D_MCAD14 0x0200 +#define CONTROL_PADCONF_SAD2D_MCAD15 0x0202 +#define CONTROL_PADCONF_SAD2D_MCAD16 0x0204 +#define CONTROL_PADCONF_SAD2D_MCAD17 0x0206 +#define CONTROL_PADCONF_SAD2D_MCAD18 0x0208 +#define CONTROL_PADCONF_SAD2D_MCAD19 0x020A +#define CONTROL_PADCONF_SAD2D_MCAD20 0x020C +#define CONTROL_PADCONF_SAD2D_MCAD21 0x020E +#define CONTROL_PADCONF_SAD2D_MCAD22 0x0210 +#define CONTROL_PADCONF_SAD2D_MCAD23 0x0212 +#define CONTROL_PADCONF_SAD2D_MCAD24 0x0214 +#define CONTROL_PADCONF_SAD2D_MCAD25 0x0216 +#define CONTROL_PADCONF_SAD2D_MCAD26 0x0218 +#define CONTROL_PADCONF_SAD2D_MCAD27 0x021A +#define CONTROL_PADCONF_SAD2D_MCAD28 0x021C +#define CONTROL_PADCONF_SAD2D_MCAD29 0x021E +#define CONTROL_PADCONF_SAD2D_MCAD30 0x0220 +#define CONTROL_PADCONF_SAD2D_MCAD31 0x0222 +#define CONTROL_PADCONF_SAD2D_MCAD32 0x0224 +#define CONTROL_PADCONF_SAD2D_MCAD33 0x0226 +#define CONTROL_PADCONF_SAD2D_MCAD34 0x0228 +#define CONTROL_PADCONF_SAD2D_MCAD35 0x022A +#define CONTROL_PADCONF_SAD2D_MCAD36 0x022C +#define CONTROL_PADCONF_SAD2D_CLK26MI 0x022E +#define CONTROL_PADCONF_SAD2D_NRESPWRON 0x0230 +#define CONTROL_PADCONF_SAD2D_NRESPWARM 0x0232 +#define CONTROL_PADCONF_SAD2D_ARMNIRQ 0x0234 +#define CONTROL_PADCONF_SAD2D_UMAFIQ 0x0236 +#define CONTROL_PADCONF_SAD2D_SPINT 0x0238 +#define CONTROL_PADCONF_SAD2D_FRINT 0x023A +#define CONTROL_PADCONF_SAD2D_DMAREQ0 0x023C +#define CONTROL_PADCONF_SAD2D_DMAREQ1 0x023E +#define CONTROL_PADCONF_SAD2D_DMAREQ2 0x0240 +#define CONTROL_PADCONF_SAD2D_DMAREQ3 0x0242 +#define CONTROL_PADCONF_SAD2D_NTRST 0x0244 +#define CONTROL_PADCONF_SAD2D_TDI 0x0246 +#define CONTROL_PADCONF_SAD2D_TDO 0x0248 +#define CONTROL_PADCONF_SAD2D_TMS 0x024A +#define CONTROL_PADCONF_SAD2D_TCK 0x024C +#define CONTROL_PADCONF_SAD2D_RTCK 0x024E +#define CONTROL_PADCONF_SAD2D_MSTDBY 0x0250 +#define CONTROL_PADCONF_SAD2D_IDLEREQ 0x0252 +#define CONTROL_PADCONF_SAD2D_IDLEACK 0x0254 +#define CONTROL_PADCONF_SAD2D_MWRITE 0x0256 +#define CONTROL_PADCONF_SAD2D_SWRITE 0x0258 +#define CONTROL_PADCONF_SAD2D_MREAD 0x025A +#define CONTROL_PADCONF_SAD2D_SREAD 0x025C +#define CONTROL_PADCONF_SAD2D_MBUSFLAG 0x025E +#define CONTROL_PADCONF_SAD2D_SBUSFLAG 0x0260 +#define CONTROL_PADCONF_SAD2D_SWAKEUP 0x0A4C + +#define CONTROL_PADCONF_SYS_32K 0x0A04 +#define CONTROL_PADCONF_SYS_CLKREQ 0x0A06 +#define CONTROL_PADCONF_SYS_NRESWARM 0x0A08 +#define CONTROL_PADCONF_SYS_BOOT0 0x0A0A +#define CONTROL_PADCONF_SYS_BOOT1 0x0A0C +#define CONTROL_PADCONF_SYS_BOOT2 0x0A0E +#define CONTROL_PADCONF_SYS_BOOT3 0x0A10 +#define CONTROL_PADCONF_SYS_BOOT4 0x0A12 +#define CONTROL_PADCONF_SYS_BOOT5 0x0A14 +#define CONTROL_PADCONF_SYS_BOOT6 0x0A16 +#define CONTROL_PADCONF_SYS_OFF_MODE 0x0A18 +#define CONTROL_PADCONF_SYS_CLKOUT1 0x0A1A +#define CONTROL_PADCONF_SYS_NIRQ 0x01E0 +#define CONTROL_PADCONF_SYS_CLKOUT2 0x01E2 + +#define CONTROL_PADCONF_JTAG_NTRST 0x0A1C +#define CONTROL_PADCONF_JTAG_TCK 0x0A1E +#define CONTROL_PADCONF_JTAG_TMS_TMSC 0x0A20 +#define CONTROL_PADCONF_JTAG_TDI 0x0A22 +#define CONTROL_PADCONF_JTAG_EMU0 0x0A24 +#define CONTROL_PADCONF_JTAG_EMU1 0x0A26 +#define CONTROL_PADCONF_JTAG_RTCK 0x0A4E +#define CONTROL_PADCONF_JTAG_TDO 0x0A50 + + + + +int +omap3_scm_padconf_set(uint32_t padconf, unsigned int mode, unsigned int state); + +int +omap3_scm_padconf_set_gpiomode(uint32_t gpio, unsigned int state); + + +int +omap3_scm_padconf_get(uint32_t padconf, unsigned int *mode, unsigned int *state); + + + +#endif /* _OMAP3_PINMUX_H_ */ Index: sys/arm/cortexa8/omap3/std.omap3 =================================================================== --- sys/arm/cortexa8/omap3/std.omap3 (revision 0) +++ sys/arm/cortexa8/omap3/std.omap3 (revision 0) @@ -0,0 +1,19 @@ +# Cortex-A8 Omap3 generic configuration +#$FreeBSD$ +files "../cortexa8/omap3/files.omap3" +include "../cortexa8/std.cortexa8" +cpu CPU_CORTEXA8_OMAP3 +makeoption ARM_LITTLE_ENDIAN + +# +# Physical memory starts at 0x80000000. We assume images are loaded at +# 0x80200000, e.g. from u-boot with 'fatload mmc 0 0x80200000 kernel.bin' +# +# +options PHYSADDR=0x80000000 +options KERNPHYSADDR=0x80200000 +makeoptions KERNPHYSADDR=0x80200000 +options KERNVIRTADDR=0xc0200000 # Used in ldscript.arm +makeoptions KERNVIRTADDR=0xc0200000 + +options STARTUP_PAGETABLE_ADDR=0x80000000 Index: sys/arm/cortexa8/omap3/omap3_space.c =================================================================== --- sys/arm/cortexa8/omap3/omap3_space.c (revision 0) +++ sys/arm/cortexa8/omap3/omap3_space.c (revision 0) @@ -0,0 +1,128 @@ +/* $NetBSD: obio_space.c,v 1.6 2003/07/15 00:25:05 lukem Exp $ */ + +/*- + * Copyright (c) 2001, 2002, 2003 Wasabi Systems, Inc. + * All rights reserved. + * + * Written by Jason R. Thorpe for Wasabi Systems, Inc. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed for the NetBSD Project by + * Wasabi Systems, Inc. + * 4. The name of Wasabi Systems, Inc. may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC + * 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. + */ + +/* + * bus_space functions for OMAP3 devices + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include + +#include + +#include +#include + + +/* Proto types for all the bus_space structure functions */ +bs_protos(generic); +bs_protos(generic_armv7); + +struct bus_space omap3_bs_tag = { + /* cookie */ + .bs_cookie = (void *) 0, + + /* mapping/unmapping */ + .bs_map = generic_bs_map, + .bs_unmap = generic_bs_unmap, + .bs_subregion = generic_bs_subregion, + + /* allocation/deallocation */ + .bs_alloc = generic_bs_alloc, + .bs_free = generic_bs_free, + + /* barrier */ + .bs_barrier = generic_bs_barrier, + + /* read (single) */ + .bs_r_1 = generic_bs_r_1, + .bs_r_2 = generic_armv7_bs_r_2, + .bs_r_4 = generic_bs_r_4, + .bs_r_8 = NULL, + + /* read multiple */ + .bs_rm_1 = generic_bs_rm_1, + .bs_rm_2 = generic_armv7_bs_rm_2, + .bs_rm_4 = generic_bs_rm_4, + .bs_rm_8 = NULL, + + /* read region */ + .bs_rr_1 = generic_bs_rr_1, + .bs_rr_2 = generic_armv7_bs_rr_2, + .bs_rr_4 = generic_bs_rr_4, + .bs_rr_8 = NULL, + + /* write (single) */ + .bs_w_1 = generic_bs_w_1, + .bs_w_2 = generic_armv7_bs_w_2, + .bs_w_4 = generic_bs_w_4, + .bs_w_8 = NULL, + + /* write multiple */ + .bs_wm_1 = generic_bs_wm_1, + .bs_wm_2 = generic_armv7_bs_wm_2, + .bs_wm_4 = generic_bs_wm_4, + .bs_wm_8 = NULL, + + /* write region */ + .bs_wr_1 = generic_bs_wr_1, + .bs_wr_2 = generic_armv7_bs_wr_2, + .bs_wr_4 = generic_bs_wr_4, + .bs_wr_8 = NULL, + + /* set multiple */ + /* XXX not implemented */ + + /* set region */ + .bs_sr_1 = NULL, + .bs_sr_2 = generic_armv7_bs_sr_2, + .bs_sr_4 = generic_bs_sr_4, + .bs_sr_8 = NULL, + + /* copy */ + .bs_c_1 = NULL, + .bs_c_2 = generic_armv7_bs_c_2, + .bs_c_4 = NULL, + .bs_c_8 = NULL, +}; + Index: sys/arm/cortexa8/omap3/omap3var.h =================================================================== --- sys/arm/cortexa8/omap3/omap3var.h (revision 0) +++ sys/arm/cortexa8/omap3/omap3var.h (revision 0) @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2010 + * Ben Gray . + * All rights reserved. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Ben Gray. + * 4. The name of the company nor the name of the author may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY BEN GRAY ``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 BEN GRAY 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 _OMAP3VAR_H_ +#define _OMAP3VAR_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +/* + * Random collection of functions and definitions ... needs cleanup + * + * + * + */ + + +extern struct bus_space omap3_bs_tag; + +uint32_t +omap3_sdram_size(void); + +void +omap3_mask_all_intr(void); + +void +omap3_post_filter_intr(void *arg); + +int +omap3_setup_intr(device_t dev, device_t child, + struct resource *res, int flags, driver_filter_t *filt, + driver_intr_t *intr, void *arg, void **cookiep); + +int +omap3_teardown_intr(device_t dev, device_t child, struct resource *res, + void *cookie); + + + + +struct omap3_ivar { + struct resource_list resources; + uint32_t addr; + int irq; +}; +#define OMAP3_IVAR(d) ((struct omap3_ivar *) device_get_ivars(d)) + +enum { + OMAP3_IVAR_ADDR, /* base physical address */ + OMAP3_IVAR_IRQ /* irq/gpio pin assignment */ +}; + + + + + +#endif /* _OMAP3VAR_H_ */ Index: sys/arm/cortexa8/omap3/omap3_gpio.c =================================================================== --- sys/arm/cortexa8/omap3/omap3_gpio.c (revision 0) +++ sys/arm/cortexa8/omap3/omap3_gpio.c (revision 0) @@ -0,0 +1,997 @@ +/* + * Copyright (c) 2010 + * Ben Gray . + * All rights reserved. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Ben Gray. + * 4. The name of the company nor the name of the author may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY BEN GRAY ``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 BEN GRAY 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. + */ + +/** + * Very simple GPIO (general purpose IO) driver module for the TI OMAP3530 SoC. + * + * Currently this driver only does the basics, get a value on a pin & set a + * value on a pin. Hopefully over time I'll expand this to be a bit more generic + * and support interrupts and other various bits on the SoC can do ... in the + * meantime this is all you get. + * + * Also beware, the OMAP3530 datasheet lists GPIO banks 1-6, whereas I've used + * 0-5 here in the code. + * + * External Usage + * ~~~~~~~~~~~~~~ + * - Call omap3_gpio_request() to get 'exclusive' access to the GPIO pin, only + * one person can call omap3_gpio_request() on the same pin. However currently + * this module works on the honor system, there is nothing stopping another + * module from changing the state of the pin using the pin number. + * - Use omap3_gpio_direction_output or omap3_gpio_direction_input to change + * the mode of the pin, from an output to an input and vice verse. + * - Use omap3_gpio_pin_get() to get the level of an input pin. + * - Use omap3_gpio_pin_set() to set the level of an output GPIO pin. + * - Call omap3_gpio_free() to release 'exclusive' access to the GPIO pin. + * + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + + +/** + * The TI OMAP3530 has a maximum of 192 IO pins, seperated accross 6 register + * sets. + */ +#define OMAP3_GPIO_MAX_PINS 192 + + +/** + * Macros for converting a pin value (0-195) to a register bank (0-5) and a + * bitmask (1,2,4,8, etc). + */ +#define OMAP3_GPIO_PIN2MASK(p) (1UL << ((p) & 0x1F)) +#define OMAP3_GPIO_PIN2BANK(p) ((p) >> 5) + + +/** + * GPIO device driver context, a pointer to this is stored globally as the + * driver is never intented to be unloaded (see g_omap3_gpio_sc). + */ +struct omap3_gpio_softc { + device_t sc_dev; + /* Annoyingly GPIO1 is in the L4-WAKEUP memory space, whereas all the others + * are in the L4-PERIPH space ... so we need seperate mappings for GPIO1 and + * GPIO2-6. + */ + bus_space_tag_t sc_iotag; + bus_space_handle_t sc_ioh_gpio1; + bus_space_handle_t sc_ioh_gpio2_6; + + struct resource* sc_irq; + + uint32_t sc_gpio_setup[(OMAP3_GPIO_MAX_PINS / 32)]; + + void (*sc_callbacks[OMAP3_GPIO_MAX_PINS])(unsigned int, unsigned int, void*); + void* sc_callback_data[OMAP3_GPIO_MAX_PINS]; + + uint32_t sc_debounce[(OMAP3_GPIO_MAX_PINS / 32)]; + + struct mtx sc_mtx; + + +}; + +static struct omap3_gpio_softc *g_omap3_gpio_sc = NULL; + + +/** + * Function prototypes + * + */ +static void omap3_gpio_intr(void *); + + +/** + * omap3_gpio_readl - reads a 32-bit value from one of the GPIO registers + * @sc: gpio device context + * @bank: the bank to read from, values 0 to 5. + * @off: the byte offset within the register bank to read from. + * + * + * + * LOCKING: + * Read only, no locking required + * + * RETURNS: + * 32-bit value read from the register. + */ +static uint32_t +omap3_gpio_readl(struct omap3_gpio_softc *sc, uint32_t bank, bus_size_t off) +{ + switch (bank) { + case 0: + return bus_space_read_4(sc->sc_iotag, sc->sc_ioh_gpio1, off); + case 1: + return bus_space_read_4(sc->sc_iotag, sc->sc_ioh_gpio2_6, off); + case 2: + return bus_space_read_4(sc->sc_iotag, sc->sc_ioh_gpio2_6, + ((OMAP35XX_GPIO3_HWBASE - OMAP35XX_GPIO2_HWBASE) + + off)); + case 3: + return bus_space_read_4(sc->sc_iotag, sc->sc_ioh_gpio2_6, + ((OMAP35XX_GPIO4_HWBASE - OMAP35XX_GPIO2_HWBASE) + + off)); + case 4: + return bus_space_read_4(sc->sc_iotag, sc->sc_ioh_gpio2_6, + ((OMAP35XX_GPIO5_HWBASE - OMAP35XX_GPIO2_HWBASE) + + off)); + case 5: + return bus_space_read_4(sc->sc_iotag, sc->sc_ioh_gpio2_6, + ((OMAP35XX_GPIO6_HWBASE - OMAP35XX_GPIO2_HWBASE) + + off)); + default: + panic("%s: Invalid gpio module", device_get_name(sc->sc_dev)); + return(0); + } + +} + +/** + * omap3_gpio_writel - writes a 32-bit value to one of the GPIO registers + * @sc: gpio device context + * @bank: the bank to write to, values 0 to 5. + * @off: the byte offset within the register bank to write to. + * + * + * LOCKING: + * Read only, no locking required + * + * RETURNS: + * nothing + */ +static void +omap3_gpio_writel(struct omap3_gpio_softc *sc, uint32_t bank, bus_size_t off, + uint32_t val) +{ + switch (bank) { + case 0: + bus_space_write_4(sc->sc_iotag, sc->sc_ioh_gpio1, off, val); + break; + case 1: + bus_space_write_4(sc->sc_iotag, sc->sc_ioh_gpio2_6, off, val); + break; + case 2: + bus_space_write_4(sc->sc_iotag, sc->sc_ioh_gpio2_6, + ((OMAP35XX_GPIO3_HWBASE - OMAP35XX_GPIO2_HWBASE) + + off), val); + break; + case 3: + bus_space_write_4(sc->sc_iotag, sc->sc_ioh_gpio2_6, + ((OMAP35XX_GPIO4_HWBASE - OMAP35XX_GPIO2_HWBASE) + + off), val); + break; + case 4: + bus_space_write_4(sc->sc_iotag, sc->sc_ioh_gpio2_6, + ((OMAP35XX_GPIO5_HWBASE - OMAP35XX_GPIO2_HWBASE) + + off), val); + break; + case 5: + bus_space_write_4(sc->sc_iotag, sc->sc_ioh_gpio2_6, + ((OMAP35XX_GPIO6_HWBASE - OMAP35XX_GPIO2_HWBASE) + + off), val); + break; + default: + panic("%s: Invalid gpio module", device_get_name(sc->sc_dev)); + } +} + + + + +/** + * omap3_gpio_probe - driver probe function + * @dev: gpio device handle + * + * Simply sets the name of the driver + * + * + * RETURNS: + * Returns 0 on sucess, a negative error code on failure. + */ +static int +omap3_gpio_probe(device_t dev) +{ + + device_set_desc(dev, "TI OMAP3 GPIO Controller"); + return (0); +} + +/** + * omap3_gpio_attach - driver attach function + * @dev: gpio device handle + * + * Sets up the driver data structure and initialises all the fields. + * + * RETURNS: + * Returns 0 on sucess, a negative error code on failure. + */ +static int +omap3_gpio_attach(device_t dev) +{ + struct omap3_gpio_softc *sc = device_get_softc(dev); + unsigned int i = 0; + int rid = 0; + void *ihl; + int err; + + /* Setup the basics */ + sc->sc_dev = dev; + sc->sc_iotag = &omap3_bs_tag; + + /* No gpios requested at startup */ + for (i=0; i<(OMAP3_GPIO_MAX_PINS/32); i++) + sc->sc_gpio_setup[i] = 0x00000000; + + + /* Mutex to protect the shared data structures */ + mtx_init(&sc->sc_mtx, device_get_nameunit(dev), "omap3_gpio", MTX_DEF); + + /* Map in the GPIO1 register set */ + if (bus_space_map(sc->sc_iotag, OMAP35XX_GPIO1_HWBASE, OMAP35XX_GPIO1_SIZE, + 0, &sc->sc_ioh_gpio1)) { + panic("%s: Cannot map registers", device_get_name(dev)); + } + + /* Map in the GPIO2 - GPIO6 register set */ + if (bus_space_map(sc->sc_iotag, OMAP35XX_GPIO2_HWBASE, + ((OMAP35XX_GPIO6_HWBASE + OMAP35XX_GPIO6_SIZE) - + OMAP35XX_GPIO2_HWBASE), + 0, &sc->sc_ioh_gpio2_6)) { + panic("%s: Cannot map registers", device_get_name(dev)); + } + + + /* Install interrupt handlers for all the possible interrupts */ + sc->sc_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, OMAP35XX_IRQ_GPIO1_MPU, + OMAP35XX_IRQ_GPIO6_MPU, 6, RF_ACTIVE); + if (sc->sc_irq == NULL) + panic("Unable to setup the GPIO irq handler.\n"); + + err = bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_MISC | INTR_MPSAFE, NULL, + omap3_gpio_intr, NULL, &ihl); + if (err) { + panic("%s: Cannot register IRQ", device_get_name(dev)); + } + + + + + /* TODO: Reset all the GPIO modules ... is this needed ? is it a good idea ? */ + + + /* Store the GPIO structure globally, this driver should never be unloaded */ + g_omap3_gpio_sc = sc; + + return (0); +} + + +static device_method_t g_omap3_gpio_methods[] = { + DEVMETHOD(device_probe, omap3_gpio_probe), + DEVMETHOD(device_attach, omap3_gpio_attach), + { 0, 0 } +}; + +static driver_t g_omap3_gpio_driver = { + "omap3_gpio", + g_omap3_gpio_methods, + sizeof(struct omap3_gpio_softc), +}; + +static devclass_t g_omap3_gpio_devclass; + +DRIVER_MODULE(omap3_gpio, omap3, g_omap3_gpio_driver, g_omap3_gpio_devclass, 0, 0); +MODULE_DEPEND(omap3_gpio, omap3_prcm, 1, 1, 1); + + + +/** + * omap3_gpio_request - requests 'exclusive' access to the GPIO pin. + * @pin: the pin number (0-195) + * @name: the name to give the pin (currently not used). + * + * + * + * LOCKING: + * Internally locks it's own context. + * + * RETURNS: + * 0 on success. + * -ENOMEM on driver not initialised. + * -EINVAL if pin requested is outside valid range or already in use. + */ +int +omap3_gpio_request(unsigned int pin, const char *name) +{ + struct omap3_gpio_softc *sc = g_omap3_gpio_sc; + int ret = 0; + uint32_t bank = OMAP3_GPIO_PIN2BANK(pin); + uint32_t mask = OMAP3_GPIO_PIN2MASK(pin); + + if (sc == NULL) + return(-ENOMEM); + if (pin >= OMAP3_GPIO_MAX_PINS) { + device_printf(sc->sc_dev, "Error - pin number is too large (%u)\n", pin); + return(-EINVAL); + } + + mtx_lock(&sc->sc_mtx); + + if (sc->sc_gpio_setup[bank] & mask) { + ret = -EINVAL; + } else { + /* enable the interface clock for the bank, just because there is no + * guarantee it is already enabled. + */ + switch (bank) { + case 0: + omap3_prcm_enable_clk(OMAP3_MODULE_GPIO1_ICLK); + break; + case 1: + omap3_prcm_enable_clk(OMAP3_MODULE_GPIO2_ICLK); + break; + case 2: + omap3_prcm_enable_clk(OMAP3_MODULE_GPIO3_ICLK); + break; + case 3: + omap3_prcm_enable_clk(OMAP3_MODULE_GPIO4_ICLK); + break; + case 4: + omap3_prcm_enable_clk(OMAP3_MODULE_GPIO5_ICLK); + break; + case 5: + omap3_prcm_enable_clk(OMAP3_MODULE_GPIO6_ICLK); + break; + } + + /* set the flag to say it is in use */ + sc->sc_gpio_setup[bank] |= mask; + } + + mtx_unlock(&sc->sc_mtx); + + return(ret); +} + +/** + * omap3_gpio_free - releases 'exclusive' access to the GPIO pin. + * @pin: the pin number (0-195) + * + * + * LOCKING: + * Internally locks it's own context. + * + * RETURNS: + * 0 on success. + * -ENOMEM on driver not initialised. + * -EINVAL if pin released is outside valid range or not requested in use. + */ +int +omap3_gpio_free(unsigned int pin) +{ + struct omap3_gpio_softc *sc = g_omap3_gpio_sc; + int ret = 0; + uint32_t bank = OMAP3_GPIO_PIN2BANK(pin); + uint32_t mask = OMAP3_GPIO_PIN2MASK(pin); + + if (sc == NULL) + return(-ENOMEM); + if (pin >= OMAP3_GPIO_MAX_PINS) { + device_printf(sc->sc_dev, "Error - pin number is too large (%u)\n", pin); + return(-EINVAL); + } + + mtx_lock(&sc->sc_mtx); + + if (!(sc->sc_gpio_setup[bank] & mask)) { + ret = -EINVAL; + } else { + sc->sc_gpio_setup[bank] &= ~mask; + + /* check if none of the pins are no in use and if so disable the + * interface clock. + */ + if (sc->sc_gpio_setup[bank] == 0x00000000) { + switch (bank) { + case 0: + omap3_prcm_disable_clk(OMAP3_MODULE_GPIO1_ICLK); + break; + case 1: + omap3_prcm_disable_clk(OMAP3_MODULE_GPIO2_ICLK); + break; + case 2: + omap3_prcm_disable_clk(OMAP3_MODULE_GPIO3_ICLK); + break; + case 3: + omap3_prcm_disable_clk(OMAP3_MODULE_GPIO4_ICLK); + break; + case 4: + omap3_prcm_disable_clk(OMAP3_MODULE_GPIO5_ICLK); + break; + case 5: + omap3_prcm_disable_clk(OMAP3_MODULE_GPIO6_ICLK); + break; + } + } + } + + + mtx_unlock(&sc->sc_mtx); + + return(ret); +} + + +/** + * omap3_gpio_direction_output - sets a GPIO pin to be an output. + * @pin: the pin number (0-195) + * @val: the value to drive on the output; val==0 low, val!=0 high + * + * + * LOCKING: + * Internally locks it's own context. + * + * RETURNS: + * 0 on success. + * -ENOMEM on driver not initialised. + * -EINVAL if pin is outside valid range or not reserved for use. + */ +int +omap3_gpio_direction_output(unsigned int pin, int val) +{ + struct omap3_gpio_softc *sc = g_omap3_gpio_sc; + int ret = 0; + uint32_t dir; + uint32_t bank = OMAP3_GPIO_PIN2BANK(pin); + uint32_t mask = OMAP3_GPIO_PIN2MASK(pin); + + if (sc == NULL) + return(-ENOMEM); + if (pin >= OMAP3_GPIO_MAX_PINS) { + device_printf(sc->sc_dev, "Error - pin number is too large (%u)\n", pin); + return(-EINVAL); + } + + mtx_lock(&sc->sc_mtx); + + if (sc->sc_gpio_setup[bank] & mask) { + + /* set the data value first */ + if (val) + omap3_gpio_writel(sc, bank, OMAP35XX_GPIO_SETDATAOUT, mask); + else + omap3_gpio_writel(sc, bank, OMAP35XX_GPIO_CLEARDATAOUT, mask); + + + /* set the direction of the pin as an output */ + dir = omap3_gpio_readl(sc, bank, OMAP35XX_GPIO_OE); + dir &= ~mask; + omap3_gpio_writel(sc, bank, OMAP35XX_GPIO_OE, dir); + } + else { + ret = -EINVAL; + } + + mtx_unlock(&sc->sc_mtx); + + return(ret); +} + +/** + * omap3_gpio_direction_input - sets a GPIO pin to be an input. + * @pin: the pin number (0-195) + * + * + * LOCKING: + * Internally locks it's own context. + * + * RETURNS: + * 0 on success. + * -ENOMEM on driver not initialised. + * -EINVAL if pin is outside valid range or not reserved for use. + */ +int +omap3_gpio_direction_input(unsigned int pin) +{ + struct omap3_gpio_softc *sc = g_omap3_gpio_sc; + int ret = 0; + uint32_t dir; + uint32_t bank = OMAP3_GPIO_PIN2BANK(pin); + uint32_t mask = OMAP3_GPIO_PIN2MASK(pin); + + if (sc == NULL) + return(-ENOMEM); + if (pin >= OMAP3_GPIO_MAX_PINS) + return(-EINVAL); + + mtx_lock(&sc->sc_mtx); + + if (sc->sc_gpio_setup[bank] & (1UL << (pin & 0x1F))) { + + /* set the direction of the pin as an input */ + dir = omap3_gpio_readl(sc, bank, OMAP35XX_GPIO_OE); + dir |= mask; + omap3_gpio_writel(sc, bank, OMAP35XX_GPIO_OE, dir); + } + else { + ret = -EINVAL; + } + + mtx_unlock(&sc->sc_mtx); + + return(ret); +} + +/** + * omap3_gpio_pin_get - reads the state on a GPIO pin. + * @pin: the pin number (0-195) + * + * + * LOCKING: + * Internally locks it's own context. + * + * RETURNS: + * 0 on pin state low + * 1 on pin state high + * -ENOMEM on driver not initialised. + * -EINVAL if pin is outside valid range or not reserved for use. + */ +int +omap3_gpio_pin_get(unsigned int pin) +{ + struct omap3_gpio_softc *sc = g_omap3_gpio_sc; + int ret = 0; + uint32_t bank = OMAP3_GPIO_PIN2BANK(pin); + uint32_t mask = OMAP3_GPIO_PIN2MASK(pin); + + if (sc == NULL) + return(-ENOMEM); + if (pin >= OMAP3_GPIO_MAX_PINS) + return(-EINVAL); + + mtx_lock(&sc->sc_mtx); + + if (sc->sc_gpio_setup[bank] & mask) { + + /* get the data value */ + if (omap3_gpio_readl(sc, bank, OMAP35XX_GPIO_DATAIN) & mask) + ret = 1; + else + ret = 0; + } + else { + ret = -EINVAL; + } + + mtx_unlock(&sc->sc_mtx); + + return(ret); +} + +/** + * omap3_gpio_pin_set - sets the state on a GPIO pin. + * @pin: the pin number (0-195) + * @val: the value to drive on the output; val==0 low, val!=0 high + * + * + * LOCKING: + * Internally locks it's own context. + * + * RETURNS: + * 0 on success + * -ENOMEM on driver not initialised. + * -EINVAL if pin is outside valid range or not reserved for use. + */ +int +omap3_gpio_pin_set(unsigned int pin, int val) +{ + struct omap3_gpio_softc *sc = g_omap3_gpio_sc; + int ret = 0; + uint32_t bank = OMAP3_GPIO_PIN2BANK(pin); + uint32_t mask = OMAP3_GPIO_PIN2MASK(pin); + + if (sc == NULL) + return(-ENOMEM); + if ((pin < 0) || (pin >= OMAP3_GPIO_MAX_PINS)) + return(-EINVAL); + + mtx_lock(&sc->sc_mtx); + + if (sc->sc_gpio_setup[bank] & mask) { + + /* set the data value */ + if (val) + omap3_gpio_writel(sc, bank, OMAP35XX_GPIO_SETDATAOUT, mask); + else + omap3_gpio_writel(sc, bank, OMAP35XX_GPIO_CLEARDATAOUT, mask); + } + else { + ret = -EINVAL; + } + + mtx_unlock(&sc->sc_mtx); + + return(ret); +} + + + +/** + * omap3_gpio_pin_toggle - toggles the level on an output GPIO pin. + * @pin: the pin number (0-195) + * + * + * LOCKING: + * Internally locks it's own context. + * + * RETURNS: + * 0 on success + * -ENOMEM on driver not initialised. + * -EINVAL if pin is outside valid range or not reserved for use. + */ +int +omap3_gpio_pin_toggle(unsigned int pin) +{ + struct omap3_gpio_softc *sc = g_omap3_gpio_sc; + int ret = 0; + uint32_t val; + uint32_t bank = OMAP3_GPIO_PIN2BANK(pin); + uint32_t mask = OMAP3_GPIO_PIN2MASK(pin); + + if (sc == NULL) + return(-ENOMEM); + if (pin >= OMAP3_GPIO_MAX_PINS) + return(-EINVAL); + + mtx_lock(&sc->sc_mtx); + + if (sc->sc_gpio_setup[bank] & mask) { + + /* get the data out value */ + val = omap3_gpio_readl(sc, bank, OMAP35XX_GPIO_DATAOUT); + + /* set the data value */ + if (val & mask) + omap3_gpio_writel(sc, bank, OMAP35XX_GPIO_CLEARDATAOUT, mask); + else + omap3_gpio_writel(sc, bank, OMAP35XX_GPIO_SETDATAOUT, mask); + } + else { + ret = -EINVAL; + } + + mtx_unlock(&sc->sc_mtx); + + return(ret); +} + + + +/** + * omap3_gpio_intr - interrupt handler for all 6 GPIO IRQs + * @arg: ignored + * + * Called when any of the four DMA IRQs are triggered. + * + * LOCKING: + * DMA registers protected by internal mutex + * + * RETURNS: + * nothing + */ +static void +omap3_gpio_intr(void *arg) +{ + struct omap3_gpio_softc *sc = g_omap3_gpio_sc; + uint32_t bank; + uint32_t pin; + uint32_t i; + uint32_t intr; + uint32_t din; + + void (*callback)(unsigned int, unsigned int, void*); + void *callback_data; + + mtx_lock(&sc->sc_mtx); + + for (bank = 0; bank < (OMAP3_GPIO_MAX_PINS / 32); bank++) { + + /* read the bank interrupt status */ + intr = omap3_gpio_readl(sc, bank, OMAP35XX_GPIO_IRQSTATUS1); + intr &= omap3_gpio_readl(sc, bank, OMAP35XX_GPIO_IRQENABLE1); + + /* read the current level */ + din = omap3_gpio_readl(sc, bank, OMAP35XX_GPIO_DATAIN); + + /* call any callbacks if the interrupt matches */ + if (intr != 0) { + for (i = 0; i< 32; i++) { + pin = (i + (bank * 32)); + if ((intr & (0x1 << i)) && (sc->sc_callbacks[pin] != NULL)) { + + callback = sc->sc_callbacks[pin]; + callback_data = sc->sc_callback_data[pin]; + + mtx_unlock(&sc->sc_mtx); + + callback(pin, ((din >> i) & 0x1), callback_data); + + mtx_lock(&sc->sc_mtx); + } + } + } + + /* clear the interrupt status */ + omap3_gpio_writel(sc, bank, OMAP35XX_GPIO_IRQSTATUS1, intr); + } + + mtx_unlock(&sc->sc_mtx); +} + + +/** + * omap3_gpio_pin_intr - enables interrupt generation on a pin change + * @pin: the pin number (0-195) + * @trigger: the pin trigger to use to generate interrupts, can OR multiple + * multiple triggers. Possible values are; GPIO_TRIGGER_LOWLEVEL, + * GPIO_TRIGGER_HIGHLEVEL, GPIO_TRIGGER_RISING and + * GPIO_TRIGGER_FAILING. + * @callback: callback function + * @data: user defined data that is passed in the callbaack + * + * This function automatically turns the pin into a input and enables interrupt + * generation on the change. When an interrupt does occur the callback is + * called. + * + * If a callback is called, it is done with the GPIO lock held, therefore you + * cannot call any of the omap3_gpio_* functions from the callback. + * + * LOCKING: + * Internally locks it's own context. + * + * RETURNS: + * 0 on success + * -ENOMEM on driver not initialised. + * -EINVAL if pin is outside valid range or not reserved for use. + */ +int +omap3_gpio_pin_intr(unsigned int pin, unsigned int trigger, + void (*callback)(unsigned int pin, unsigned int datain, void *data), + void *data) +{ + struct omap3_gpio_softc *sc = g_omap3_gpio_sc; + int ret = 0; + uint32_t bank = OMAP3_GPIO_PIN2BANK(pin); + uint32_t mask = OMAP3_GPIO_PIN2MASK(pin); + uint32_t reg; + + if (sc == NULL) + return(-ENOMEM); + if (pin >= OMAP3_GPIO_MAX_PINS) + return(-EINVAL); + + trigger &= 0xf; + if (trigger == 0) + return(-EINVAL); + + mtx_lock(&sc->sc_mtx); + + if (sc->sc_gpio_setup[bank] & mask) { + + /* set the callback details */ + sc->sc_callbacks[pin] = callback; + sc->sc_callback_data[pin] = data; + + /* disable interrupts on this particular pin while changing the trig */ + omap3_gpio_writel(sc, bank, OMAP35XX_GPIO_CLEARIRQENABLE1, mask); + + /* enable the interrupts */ + if (trigger & GPIO_TRIGGER_LOWLEVEL) { + reg = omap3_gpio_readl(sc, bank, OMAP35XX_GPIO_LEVELDETECT0); + reg |= mask; + omap3_gpio_writel(sc, bank, OMAP35XX_GPIO_LEVELDETECT0, reg); + } + if (trigger & GPIO_TRIGGER_HIGHLEVEL) { + reg = omap3_gpio_readl(sc, bank, OMAP35XX_GPIO_LEVELDETECT1); + reg |= mask; + omap3_gpio_writel(sc, bank, OMAP35XX_GPIO_LEVELDETECT1, reg); + } + if (trigger & GPIO_TRIGGER_RISING) { + reg = omap3_gpio_readl(sc, bank, OMAP35XX_GPIO_RISINGDETECT); + reg |= mask; + omap3_gpio_writel(sc, bank, OMAP35XX_GPIO_RISINGDETECT, reg); + } + if (trigger & GPIO_TRIGGER_FALLING) { + reg = omap3_gpio_readl(sc, bank, OMAP35XX_GPIO_FALLINGDETECT); + reg |= mask; + omap3_gpio_writel(sc, bank, OMAP35XX_GPIO_FALLINGDETECT, reg); + } + + /* enable the interrupt again */ + omap3_gpio_writel(sc, bank, OMAP35XX_GPIO_SETIRQENABLE1, mask); + } + else { + ret = -EINVAL; + } + + mtx_unlock(&sc->sc_mtx); + + return(ret); +} + + + +/** + * omap3_gpio_pin_debounce - enables/disables debouncing on a pin + * @pin: the pin number (0-195) + * @enable: non-zero value to enable, 0 to disable + * @interval: the debounce interval in microseconds, used for all pins on the bank + * + * + * + * LOCKING: + * Internally locks it's own context. + * + * RETURNS: + * 0 on success + * -ENOMEM on driver not initialised. + * -EINVAL if pin is outside valid range or not reserved for use. + */ +int +omap3_gpio_pin_debounce(unsigned int pin, int enable, unsigned int interval) +{ + struct omap3_gpio_softc *sc = g_omap3_gpio_sc; + int ret = 0; + uint32_t bank = OMAP3_GPIO_PIN2BANK(pin); + uint32_t mask = OMAP3_GPIO_PIN2MASK(pin); + uint32_t reg; + + if (sc == NULL) + return(-ENOMEM); + if (pin >= OMAP3_GPIO_MAX_PINS) + return(-EINVAL); + + mtx_lock(&sc->sc_mtx); + + if (sc->sc_gpio_setup[bank] & mask) { + + if (enable) { + + /* set the debounce flag */ + sc->sc_debounce[bank] |= mask; + + /* if enabling we need to check that the functional clock is enabled */ + switch (bank) { + case 0: + omap3_prcm_enable_clk(OMAP3_MODULE_GPIO1_FCLK); + break; + case 1: + omap3_prcm_enable_clk(OMAP3_MODULE_GPIO2_FCLK); + break; + case 2: + omap3_prcm_enable_clk(OMAP3_MODULE_GPIO3_FCLK); + break; + case 3: + omap3_prcm_enable_clk(OMAP3_MODULE_GPIO4_FCLK); + break; + case 4: + omap3_prcm_enable_clk(OMAP3_MODULE_GPIO5_FCLK); + break; + case 5: + omap3_prcm_enable_clk(OMAP3_MODULE_GPIO6_FCLK); + break; + } + + /* enable debounce in the register */ + reg = omap3_gpio_readl(sc, bank, OMAP35XX_GPIO_DEBOUNCENABLE); + reg |= mask; + omap3_gpio_writel(sc, bank, OMAP35XX_GPIO_DEBOUNCENABLE, reg); + + /* finally set the debounce time, this affects all pins on the bank, + * but hopefully the caller knows that. + */ + interval /= 31; + if (interval != 0) + interval -= 1; + if (interval > 0xff) + interval = 0xff; + omap3_gpio_writel(sc, bank, OMAP35XX_GPIO_DEBOUNCINGTIME, interval); + + } else { + + /* clear the debounce flag */ + sc->sc_debounce[bank] &= ~mask; + + /* if debouncing is no longer needed on the bank disable the clock */ + if (sc->sc_debounce[bank] == 0x00000000) { + switch (bank) { + case 0: + omap3_prcm_disable_clk(OMAP3_MODULE_GPIO1_FCLK); + break; + case 1: + omap3_prcm_disable_clk(OMAP3_MODULE_GPIO2_FCLK); + break; + case 2: + omap3_prcm_disable_clk(OMAP3_MODULE_GPIO3_FCLK); + break; + case 3: + omap3_prcm_disable_clk(OMAP3_MODULE_GPIO4_FCLK); + break; + case 4: + omap3_prcm_disable_clk(OMAP3_MODULE_GPIO5_FCLK); + break; + case 5: + omap3_prcm_disable_clk(OMAP3_MODULE_GPIO6_FCLK); + break; + } + } + + /* disable debounce in the register */ + reg = omap3_gpio_readl(sc, bank, OMAP35XX_GPIO_DEBOUNCENABLE); + reg &= ~mask; + omap3_gpio_writel(sc, bank, OMAP35XX_GPIO_DEBOUNCENABLE, reg); + } + + } + else { + ret = -EINVAL; + } + + mtx_unlock(&sc->sc_mtx); + + return(ret); +} + + Index: sys/arm/cortexa8/cortexa8_machdep.c =================================================================== --- sys/arm/cortexa8/cortexa8_machdep.c (revision 0) +++ sys/arm/cortexa8/cortexa8_machdep.c (revision 0) @@ -0,0 +1,548 @@ +/*- + * Copyright (c) 2009 Guillaume Ballet + * All rights reserved. + * + * 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 AUTHOR 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 AUTHOR 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 +__FBSDID("$FreeBSD$"); + +#define _ARM32_BUS_DMA_PRIVATE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define DEBUG_INITARM +//#define VERBOSE_INIT_ARM + +#include +#include + +#include + +#ifdef VERBOSE_INIT_ARM +#define DPRINTF(x) printf(x) +#else +#define DPRINTF(x) +#endif + +struct pcpu __pcpu; +struct pcpu *pcpup = &__pcpu; + +/* Physical page ranges */ +vm_paddr_t phys_avail[4]; +vm_paddr_t dump_avail[4]; + +struct pv_addr systempage; + +#define FIQ_STACK_SIZE 1 +#define IRQ_STACK_SIZE 1 +#define ABT_STACK_SIZE 1 +#define UND_STACK_SIZE 1 + +extern int _start[]; +extern int _end[]; + +extern void beagle_dump_ttb(vm_offset_t va); + +extern u_int data_abort_handler_address; +extern u_int prefetch_abort_handler_address; +extern u_int undefined_handler_address; + +static struct pv_addr fiqstack; /* Stack page descriptors for all modes */ +static struct pv_addr irqstack; +static struct pv_addr undstack; +static struct pv_addr abtstack; +static struct pv_addr kernelstack; +static struct pv_addr kernel_l1pt; /* Level-1 page table entry */ + +#define KERNEL_PT_SYS 0 /* Page table for mapping proc0 zero page */ +#define KERNEL_PT_KERN 1 +#define KERNEL_PT_KERN_NUM 22 +#define KERNEL_PT_AFKERNEL KERNEL_PT_KERN + KERNEL_PT_KERN_NUM /* L2 table for mapping after kernel */ +#define KERNEL_PT_AFKERNEL_NUM 5 + +/* this should be evenly divisable by PAGE_SIZE / L2_TABLE_SIZE_REAL (or 4) */ +#define NUM_KERNEL_PTS (KERNEL_PT_AFKERNEL + KERNEL_PT_AFKERNEL_NUM) + +static struct pv_addr kernel_page_tables[NUM_KERNEL_PTS]; /* Level-2 page table entries for the kernel */ + +static struct trapframe proc0_tf; + +#define PHYS2VIRT(x) ((x - KERNPHYSADDR) + KERNVIRTADDR) +#define VIRT2PHYS(x) ((x - KERNVIRTADDR) + KERNPHYSADDR) + +/* Macro stolen from the Xscale part, used to simplify TLB allocation */ +#define valloc_pages(var, np) \ + alloc_pages((var).pv_pa, (np)); \ + (var).pv_va = PHYS2VIRT((var).pv_pa); \ + DPRINTF(("va=%p pa=%p\n", (void*)(var).pv_va, (void*)(var).pv_pa)); + +#define alloc_pages(var, np) \ + (var) = freemempos; \ + freemempos += (np * PAGE_SIZE); \ + memset((char *)(var), 0, ((np) * PAGE_SIZE)); + +#define round_L_page(x) (((x) + L2_L_OFFSET) & L2_L_FRAME) + +#define VERBOSE_INIT_ARM + +static const struct pmap_devmap omap3_devmap[] = { + /* + * For the moment, map devices with PA==VA. + */ + { + /* 16MB of L4, covering all L4 core registers */ + .pd_va = OMAP35XX_L4_CORE_VBASE, + .pd_pa = OMAP35XX_L4_CORE_HWBASE, + .pd_size = OMAP35XX_L4_CORE_SIZE, + .pd_prot = VM_PROT_READ|VM_PROT_WRITE, + .pd_cache = PTE_NOCACHE + }, + { + /* 1MB of L4, covering the periph registers */ + .pd_va = OMAP35XX_L4_PERIPH_VBASE, + .pd_pa = OMAP35XX_L4_PERIPH_HWBASE, + .pd_size = OMAP35XX_L4_PERIPH_SIZE, + .pd_prot = VM_PROT_READ|VM_PROT_WRITE, + .pd_cache = PTE_NOCACHE + }, + { + /* 64Kb of L3, covering the SDRAM controller registers */ + .pd_va = OMAP35XX_L4_WAKEUP_VBASE, + .pd_pa = OMAP35XX_L4_WAKEUP_HWBASE, + .pd_size = OMAP35XX_L4_PERIPH_SIZE, + .pd_prot = VM_PROT_READ|VM_PROT_WRITE, + .pd_cache = PTE_NOCACHE + }, + { + /* 64Kb of L3, covering the SDRAM controller registers */ + .pd_va = OMAP35XX_SDRC_VBASE, + .pd_pa = OMAP35XX_SDRC_HWBASE, + .pd_size = OMAP35XX_SDRC_SIZE, + .pd_prot = VM_PROT_READ|VM_PROT_WRITE, + .pd_cache = PTE_NOCACHE + }, + { 0, 0, 0, 0, 0 } /* Array terminator */ +}; + +int beagle_printf(const char *format, ...); +static void * +initarm_boilerplate(void *arg1, void *arg2) +{ + vm_offset_t freemempos; + vm_offset_t freemem_pt; + vm_offset_t lastaddr; + vm_offset_t offset; + uint32_t i, j; + volatile uint32_t cpsr; + uint32_t sdram_size; + u_int32_t l1pagetable; + size_t textsize; + size_t totalsize; + + + boothowto = 0 | RB_SINGLE; + bootverbose++; + + /* + * Sets the CPU functions based on the CPU ID, this code is all + * in the cpufunc.c file. The function sets the cpufunc structure + * to match the machine and also initialises the pmap/pte code. + */ + set_cpufuncs(); + + + /* + * fake_preload_metadata() creates a fake boot descriptor table and + * returns the last address in the kernel. + */ + lastaddr = fake_preload_metadata(); + + + /* + * Initialize the MI portions of a struct per cpu structure. + */ + pcpu_init(pcpup, 0, sizeof(struct pcpu)); + PCPU_SET(curthread, &thread0); + + + +#ifdef VERBOSE_INIT_ARM + __asm __volatile("mrc p15, 0, %0, c1, c0, 0 ;" : "=r" (cpsr)); + printf("cp15:c1:c0=0x%08x\n", cpsr); + printf("PMAP_DOMAIN_KERNEL=0x%08x\n", PMAP_DOMAIN_KERNEL); +#endif + + + /* + * Initialize freemempos. Pages are allocated from the end of the RAM's + * first 64MB, as it is what is covered by the default TLB in locore.S. + */ + freemempos = VIRT2PHYS(round_L_page(lastaddr)); + + printf("freemempos=0x%08x %u %u\n", (unsigned int)freemempos, L1_S_SIZE, L1_TABLE_SIZE); + + /* Reserve L1 table pages now, as freemempos is 64K-aligned */ + valloc_pages(kernel_l1pt, L1_TABLE_SIZE / PAGE_SIZE); + printf("l1pa=0x%08x l1va=0x%08x\n", (unsigned int)kernel_l1pt.pv_pa, (unsigned int)kernel_l1pt.pv_va); + + /* + * Reserve the paging system pages, page #0 is reserved as a L2 table for + * the exception vector. Now allocate L2 page tables; they are linked to L1 below + */ + for (i = 0; i < NUM_KERNEL_PTS; ++i) { + j = (i % (PAGE_SIZE / L2_TABLE_SIZE_REAL)); + + if (j == 0) { + valloc_pages(kernel_page_tables[i], L2_TABLE_SIZE / PAGE_SIZE); + } else { + + kernel_page_tables[i].pv_pa = kernel_page_tables[i - j].pv_pa + + (j * L2_TABLE_SIZE_REAL); + kernel_page_tables[i].pv_va = kernel_page_tables[i - j].pv_va + + (j * L2_TABLE_SIZE_REAL); + } +#ifdef VERBOSE_INIT_ARM + printf("kernel_page_tables[%d] PA:0x%08x VA:0x%08x\n", i, kernel_page_tables[i].pv_pa, kernel_page_tables[i].pv_va); +#endif + } + + /* base of allocated pt's */ + freemem_pt = freemempos; + +/* + for (i=0; ipcb_flags = 0; + thread0.td_frame = &proc0_tf; + pcpup->pc_curpcb = thread0.td_pcb; + + /* Exception vector */ +#ifdef VERBOSE_INIT_ARM + printf("\nException vector at (0x%08x)\n", ((unsigned int *)systempage.pv_va)[0]); +#endif + arm_vector_init(ARM_VECTORS_HIGH, ARM_VEC_ALL); + + /* First unbacked address of KVM */ + pmap_curmaxkvaddr = KERNVIRTADDR + 0x100000 * NUM_KERNEL_PTS; + + /* Get the size of the SDRAM */ + sdram_size = omap3_sdram_size(); +#ifdef VERBOSE_INIT_ARM + printf("\nSDRAM size 0x%08X, %dMB\n", sdram_size, (sdram_size / 1024 / 1024)); +#endif + + /* Physical ranges of available memory. */ + phys_avail[0] = freemempos; + phys_avail[1] = PHYSADDR + sdram_size; + phys_avail[2] = 0; + phys_avail[3] = 0; + + dump_avail[0] = PHYSADDR; + dump_avail[1] = PHYSADDR + sdram_size; + dump_avail[2] = 0; + dump_avail[3] = 0; + + physmem = sdram_size / PAGE_SIZE; + + + pmap_bootstrap((freemempos&0x00ffffff)|0xc0000000, /* start address */ + KERNVIRTADDR+0x10000000, /* end address */ + &kernel_l1pt); + + init_param1(); + init_param2(physmem); + + /* Locking system */ + mutex_init(); + + /* Kernel debugger */ + kdb_init(); + + /* initarm returns the address of the kernel stack */ + return ((void *)(kernelstack.pv_va + USPACE_SVC_STACK_TOP - + sizeof(struct pcb))); +} + +void *initarm(void *arg1, void *arg2) +{ + return initarm_boilerplate(arg1, arg2); +} + +struct arm32_dma_range * +bus_dma_get_range(void) +{ + /* TODO: Need implementation ? */ + return (NULL); +} + +int +bus_dma_get_range_nb(void) +{ + /* TODO: Need implementation ? */ + return (0); +} + Index: sys/arm/cortexa8/std.cortexa8.orig =================================================================== Index: sys/arm/cortexa8/std.cortexa8 =================================================================== --- sys/arm/cortexa8/std.cortexa8 (revision 0) +++ sys/arm/cortexa8/std.cortexa8 (revision 0) @@ -0,0 +1,3 @@ +# $FreeBSD$ + +# options ARM_CACHE_LOCK_ENABLE Index: sys/arm/cortexa8/cortexa8_uart.c.orig =================================================================== Index: sys/arm/cortexa8/cortexa8_uart.c =================================================================== --- sys/arm/cortexa8/cortexa8_uart.c (revision 0) +++ sys/arm/cortexa8/cortexa8_uart.c (revision 0) @@ -0,0 +1,252 @@ +/* + Copyright 2001, 2002 Georges Menie (www.menie.org) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + putchar is the only external dependency for this file, + if you have a working putchar, just remove the following + define. If the function should be called something else, + replace outbyte(c) by your own function call. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +void beagle_putchar(unsigned char c); +void beagle_putstr(unsigned char *str); +int beagle_printf(const char *format, ...); +int beagle_sprintf(char *out, const char *format, ...); +int beagle_panic(const char *format, ...); + +static void printchar(char **str, int c) +{ + if (str) { + **str = c; + ++(*str); + } + else + { + (void)beagle_putchar(c); + } +} + +#define PAD_RIGHT 1 +#define PAD_ZERO 2 + +static int prints(char **out, const char *string, int width, int pad) +{ + register int pc = 0, padchar = ' '; + + if (width > 0) { + register int len = 0; + register const char *ptr; + for (ptr = string; *ptr; ++ptr) ++len; + if (len >= width) width = 0; + else width -= len; + if (pad & PAD_ZERO) padchar = '0'; + } + if (!(pad & PAD_RIGHT)) { + for ( ; width > 0; --width) { + printchar (out, padchar); + ++pc; + } + } + for ( ; *string ; ++string) { + printchar (out, *string); + ++pc; + } + for ( ; width > 0; --width) { + printchar (out, padchar); + ++pc; + } + + return pc; +} + +/* the following should be enough for 32 bit int */ +#define PRINT_BUF_LEN 12 + +static int printi(char **out, int i, int b, int sg, int width, int pad, int letbase) +{ + char print_buf[PRINT_BUF_LEN]; + register char *s; + register int t, neg = 0, pc = 0; + register unsigned int u = i; + + if (i == 0) { + print_buf[0] = '0'; + print_buf[1] = '\0'; + return prints (out, print_buf, width, pad); + } + + if (sg && b == 10 && i < 0) { + neg = 1; + u = -i; + } + + s = print_buf + PRINT_BUF_LEN-1; + *s = '\0'; + + while (u) { + t = u % b; + if( t >= 10 ) + t += letbase - '0' - 10; + *--s = t + '0'; + u /= b; + } + + if (neg) { + if( width && (pad & PAD_ZERO) ) { + printchar (out, '-'); + ++pc; + --width; + } + else { + *--s = '-'; + } + } + + return pc + prints (out, s, width, pad); +} + +static int print(char **out, int *varg) +{ + register int width, pad; + register int pc = 0; + register char *format = (char *)(*varg++); + char scr[2]; + + for (; *format != 0; ++format) { + if (*format == '%') { + ++format; + width = pad = 0; + if (*format == '\0') break; + if (*format == '%') goto out; + if (*format == '-') { + ++format; + pad = PAD_RIGHT; + } + while (*format == '0') { + ++format; + pad |= PAD_ZERO; + } + for ( ; *format >= '0' && *format <= '9'; ++format) { + width *= 10; + width += *format - '0'; + } + if( *format == 's' ) { + register char *s = *((char **)varg++); + pc += prints (out, s?s:"(null)", width, pad); + continue; + } + if( *format == 'd' ) { + pc += printi (out, *varg++, 10, 1, width, pad, 'a'); + continue; + } + if( *format == 'x' ) { + pc += printi (out, *varg++, 16, 0, width, pad, 'a'); + continue; + } + if( *format == 'X' ) { + pc += printi (out, *varg++, 16, 0, width, pad, 'A'); + continue; + } + if( *format == 'u' ) { + pc += printi (out, *varg++, 10, 0, width, pad, 'a'); + continue; + } + if( *format == 'c' ) { + /* char are converted to int then pushed on the stack */ + scr[0] = *varg++; + scr[1] = '\0'; + pc += prints (out, scr, width, pad); + continue; + } + } + else { + out: + printchar (out, *format); + ++pc; + } + } + if (out) **out = '\0'; + return pc; +} + +/* assuming sizeof(void *) == sizeof(int) */ + +int beagle_sprintf(char *out, const char *format, ...) +{ + register int *varg = (int *)(&format); + return print(&out, varg); +} + +#ifdef LSR_THRE +#undef LSR_THRE +#endif +#define LSR_THRE 0x20 /* Xmit holding register empty */ + +void beagle_putchar(unsigned char c) +{ + volatile uint8_t *p_lsr = (volatile uint8_t*) (OMAP35XX_UART3_VBASE + 0x14); + volatile uint8_t *p_thr = (volatile uint8_t*) (OMAP35XX_UART3_VBASE + 0x00); + + while ((*p_lsr & LSR_THRE) == 0); + *p_thr = c; + + if (c == '\n') + { + while ((*p_lsr & LSR_THRE) == 0); + *p_thr = '\r'; + } +} + +void beagle_putstr(unsigned char *str) +{ + do { + beagle_putchar(*str++); + } while (*str != '\0'); +} + +int beagle_printf(const char *format, ...) +{ + register int *varg = (int *)(&format); + return print(0, varg); +} + +int beagle_panic(const char *format, ...) +{ + register int *varg = (int *)(&format); + beagle_putstr("PANIC: "); + print(0, varg); + + for (;;); + + return 0; +} + Index: sys/arm/cortexa8/cortexa8_ttb_debug.c.orig =================================================================== Index: sys/arm/cortexa8/cortexa8_ttb_debug.c =================================================================== --- sys/arm/cortexa8/cortexa8_ttb_debug.c (revision 0) +++ sys/arm/cortexa8/cortexa8_ttb_debug.c (revision 0) @@ -0,0 +1,298 @@ +/* + * Copyright (c) 2010 + * Ben Gray . + * All rights reserved. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Ben Gray. + * 4. The name of the company nor the name of the author may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY BEN GRAY ``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 BEN GRAY 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +void beagle_dump_ttb(vm_offset_t va); +void beagle_dump_pmap(pmap_t pm); + +void beagle_dump_ttb_at(vm_offset_t l1_va, vm_offset_t va); +void beagle_dump_pmap_addr(pmap_t pm, vm_offset_t far); + +#define PHSY2VIRT(a) (((a) - PHYSADDR) + KERNBASE) + +#if 0 + +/** + * beagle_dump_l2_entry - dumps a single L2 entry + * @va: the virtual address of top level PTE. + * @pte: the actual PTE entry. + * + * + * + * LOCKING: + * None required + * + * RETURNS: + * nothing + */ +static void +beagle_dump_l2_entry(vm_offset_t va, uint32_t pte) +{ + switch (pte & 0x3) { + case 0x1: + printf("[0x%08x]\t -> L2 L [0x%08x] {0x%08x} XN:%d TEX:%d nG:%d S:%d AP:%d SBZ:%d AP:%d C:%d B:%d\n", + va, + pte, + (pte & 0xFFFF0000), + ((pte >> 15) & 0x1), + ((pte >> 12) & 0x7), + ((pte >> 11) & 0x1), + ((pte >> 10) & 0x1), + ((pte >> 9) & 0x1), + ((pte >> 6) & 0x7), + ((pte >> 4) & 0x3), + ((pte >> 3) & 0x1), + ((pte >> 2) & 0x1)); + break; + case 0x2: + case 0x3: + printf("[0x%08x]\t -> L2 S [0x%08x] {0x%08x} nG:%d S:%d AP:%d TEX:%d AP:%d C:%d B:%d XN:%d\n", + va, + pte, + (pte & 0xFFFFF000), + ((pte >> 11) & 0x1), + ((pte >> 10) & 0x1), + ((pte >> 9) & 0x1), + ((pte >> 6) & 0x7), + ((pte >> 4) & 0x3), + ((pte >> 3) & 0x1), + ((pte >> 2) & 0x1), + ((pte >> 0) & 0x1)); + break; + } +} + +/** + * beagle_dump_l2_entries - dumps L2 entries + * @va: the virtual address of top level PTE. + * @off: the offset from the L1 level. + * + * + * + * LOCKING: + * None required + * + * RETURNS: + * nothing + */ +static void +beagle_dump_l2_entries(vm_offset_t va, vm_offset_t off) +{ + uint32_t i; + volatile uint32_t *p_pte = (volatile uint32_t*) va; + + printf("\tDumping L2 @ 0x%08x\n", va); + + for (i=0; i<256; i++) { + beagle_dump_l2_entry((off + (i * 4096)), *p_pte++); + } +} + +#endif + +/** + * beagle_dump_l1_entry - dumps an L1 entry + * @va: the virtual address of top level PTE. + * @pte: the page table entry. + * + * + * + * LOCKING: + * None required + * + * RETURNS: + * nothing + */ +static void +beagle_dump_l1_entry(vm_offset_t va, uint32_t pte) +{ + switch (pte & 0x3) { + case 0x1: + printf("[0x%08x] -> L1 P [0x%08x] {0x%08x} IMP:%d D:%d SBZ:%d NS:%d SBZ:%d\n", + va, + pte, + (pte & 0xFFFFFC00), + ((pte >> 9) & 0x1), + ((pte >> 5) & 0xF), + ((pte >> 4) & 0x1), + ((pte >> 3) & 0x1), + ((pte >> 2) & 0x1)); + //beagle_dump_l2_entries(PHSY2VIRT(pte & 0xFFFFFC00), va); + break; + case 0x2: + if (((pte >> 18) & 0x1) == 0) { + printf("[0x%08x] -> L1 S [0x%08x] {0x%08x} NS:%d 0:%d nG:%d S:%d AP2:%d TEX:%d AP:%d IMP:%d D:%d XN:%d C:%d B:%d\n", + va, + pte, + (pte & 0xFFF00000), + ((pte >> 19) & 0x1), + ((pte >> 18) & 0x1), + ((pte >> 17) & 0x1), + ((pte >> 16) & 0x1), + ((pte >> 15) & 0x1), + ((pte >> 12) & 0x7), + ((pte >> 10) & 0x3), + ((pte >> 9) & 0x1), + ((pte >> 5) & 0xF), + ((pte >> 4) & 0x1), + ((pte >> 3) & 0x1), + ((pte >> 2) & 0x1)); + } else { + printf("[0x%08x] -> L1 Ss[0x%08x] {0x%08x} EXT:%d NS:%d 1:%d nG:%d S:%d AP2:%d TEX:%d AP:%d IMP:%d EXT:%d XN:%d C:%d B:%d\n", + va, + pte, + (pte & 0xFF000000), + ((pte >> 20) & 0xF), + ((pte >> 19) & 0x1), + ((pte >> 18) & 0x1), + ((pte >> 17) & 0x1), + ((pte >> 16) & 0x1), + ((pte >> 15) & 0x1), + ((pte >> 12) & 0x7), + ((pte >> 10) & 0x3), + ((pte >> 9) & 0x1), + ((pte >> 5) & 0xF), + ((pte >> 4) & 0x1), + ((pte >> 3) & 0x1), + ((pte >> 2) & 0x1)); + } + break; + case 0x3: + printf("L1 Reservered\n"); + break; + } +} + +/** + * beagle_dump_ttb - dump the MMU L1/L2 page tables + * @va: the virtual address of top level PTE. + * + * Prints the complete MMU page table out the uart. + * + * LOCKING: + * None required + * + * RETURNS: + * nothing + */ +void +beagle_dump_ttb(vm_offset_t l1_va) +{ + uint32_t i; + volatile uint32_t *p_pte = (volatile uint32_t*) l1_va; + + printf("Dumping TTB @ 0x%08x\n", l1_va); + + for (i=0; i<4096; i++) { + beagle_dump_l1_entry((i * 1024 * 1024), *p_pte++); + } +} + +/** + * beagle_dump_ttb - dump the MMU L1/L2 page tables + * @va: the virtual address of top level PTE. + * + * Prints the complete MMU page table out the uart. + * + * LOCKING: + * None required + * + * RETURNS: + * nothing + */ +void +beagle_dump_pmap(pmap_t pm) +{ + //beagle_dump_ttb(pmap_get_l1tbl(pm)); +} + +void +beagle_dump_ttb_at(vm_offset_t l1_va, vm_offset_t va) +{ + uint32_t idx = (va >> 20); + volatile uint32_t *p_pte = (volatile uint32_t*)l1_va; + + p_pte += idx; + + printf("Dumping TTB @ 0x%08x\n", (vm_offset_t)p_pte); + + beagle_dump_l1_entry((idx * 1024 * 1024), *p_pte); +} + +void +beagle_dump_pmap_addr(pmap_t pm, vm_offset_t far) +{ + //beagle_dump_ttb_at(pmap_get_l1tbl(pm), far); +} Index: sys/arm/cortexa8/cortexa8_machdep.c.orig =================================================================== Index: sys/conf/Makefile.arm =================================================================== --- sys/conf/Makefile.arm (revision 220086) +++ sys/conf/Makefile.arm (working copy) @@ -75,7 +75,8 @@ $S/$M/$M/cpufunc_asm_sa1.S $S/$M/$M/cpufunc_asm_arm10.S \ $S/$M/$M/cpufunc_asm_xscale.S $S/$M/$M/cpufunc_asm.S \ $S/$M/$M/cpufunc_asm_xscale_c3.S $S/$M/$M/cpufunc_asm_armv5_ec.S \ - $S/$M/$M/cpufunc_asm_sheeva.S $S/$M/$M/cpufunc_asm_fa526.S + $S/$M/$M/cpufunc_asm_sheeva.S $S/$M/$M/cpufunc_asm_fa526.S \ + $S/$M/$M/cpufunc_asm_cortex_a8.S KERNEL_EXTRA=trampoline KERNEL_EXTRA_INSTALL=kernel.gz.tramp trampoline: ${KERNEL_KO}.tramp Index: sys/conf/files =================================================================== --- sys/conf/files (revision 220086) +++ sys/conf/files (working copy) @@ -1076,6 +1076,7 @@ dev/iicbus/ad7418.c optional ad7418 dev/iicbus/ds133x.c optional ds133x dev/iicbus/ds1672.c optional ds1672 +dev/iicbus/tps65950.c optional tps65950 dev/iicbus/icee.c optional icee dev/iicbus/if_ic.c optional ic dev/iicbus/iic.c optional iic Index: sys/conf/options.arm =================================================================== --- sys/conf/options.arm (revision 220086) +++ sys/conf/options.arm (working copy) @@ -17,6 +17,7 @@ CPU_XSCALE_IXP425 opt_global.h CPU_XSCALE_IXP435 opt_global.h CPU_XSCALE_PXA2X0 opt_global.h +CPU_CORTEXA8_OMAP3 opt_global.h FLASHADDR opt_global.h IXP4XX_FLASH_SIZE opt_global.h KERNPHYSADDR opt_global.h Index: sys/dev/uart/uart_dev_ns8250.c =================================================================== --- sys/dev/uart/uart_dev_ns8250.c (revision 220086) +++ sys/dev/uart/uart_dev_ns8250.c (working copy) @@ -575,6 +575,7 @@ static int ns8250_bus_ipend(struct uart_softc *sc) { + struct ns8250_softc *ns8250 = (struct ns8250_softc*)sc; struct uart_bas *bas; int ipend; uint8_t iir, lsr; @@ -596,9 +597,14 @@ if (lsr & LSR_RXRDY) ipend |= SER_INT_RXREADY; } else { - if (iir & IIR_TXRDY) + if (iir & IIR_TXRDY) { ipend |= SER_INT_TXIDLE; - else + /* + * Disable the IIR_TXRDY interrupt until + * data has been written to the TX FIFO + */ + uart_setreg(bas, REG_IER, ns8250->ier & ~(IER_ETXRDY)); + } else ipend |= SER_INT_SIGCHG; } if (ipend == 0) Index: sys/dev/mmc/mmc.c =================================================================== --- sys/dev/mmc/mmc.c (revision 220086) +++ sys/dev/mmc/mmc.c (working copy) @@ -1539,4 +1539,5 @@ DRIVER_MODULE(mmc, at91_mci, mmc_driver, mmc_devclass, NULL, NULL); +DRIVER_MODULE(mmc, omap3_mmc, mmc_driver, mmc_devclass, NULL, NULL); DRIVER_MODULE(mmc, sdhci, mmc_driver, mmc_devclass, NULL, NULL); Index: sys/dev/iicbus/tps65950.c =================================================================== --- sys/dev/iicbus/tps65950.c (revision 0) +++ sys/dev/iicbus/tps65950.c (revision 0) @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2010 + * Ben Gray . + * All rights reserved. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Ben Gray. + * 4. The name of the company nor the name of the author may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY BEN GRAY ``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 BEN GRAY 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 +__FBSDID("$FreeBSD$"); + +/* + * Texas Instruments OMAP Power Management and System Companion Device + * + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "iicbus_if.h" + +//#define IIC_M_WR 0 /* write operation */ + +#define TPS65950_ADDR 0x4A /* slave address */ + +#define MAX_IIC_DATA_SIZE 4 + +struct tps65950_softc { + device_t sc_dev; + + /* the following is the init function hook so it is run after interupts + * and the clocks have been enabled. + */ + struct intr_config_hook sc_ich; + +}; + +/** + * tps65950_probe - probe function for the driver + * @dev: i2c device handle + * + * + * + * LOCKING: + * Called from timer context + * + * RETURNS: + * BUS_PROBE_NOWILDCARD + */ +static int +tps65950_probe(device_t dev) +{ + device_set_desc(dev, "TI OMAP Power Management and System Companion Device"); + return (BUS_PROBE_NOWILDCARD); +} + +/** + * tps65950_read - reads one or more bytes from the remote IC + * @dev: i2c device handle + * @addr: the address to read from + * @data: buffer to put the received bytes in (must be at least as big as size) + * @size: the number of bytes to read + * + * + * LOCKING: + * Called from timer context + * + * RETURNS: + * EH_HANDLED or EH_NOT_HANDLED + */ +static int +tps65950_read(device_t dev, uint8_t addr, uint8_t *data, uint8_t size) +{ + struct iic_msg msgs[2] = { + { TPS65950_ADDR, IIC_M_WR, 1, &addr }, + { TPS65950_ADDR, IIC_M_RD, size, data } + }; + + return (iicbus_transfer(dev, msgs, 2)); +} + +/** + * tps65950_write - attach function for the driver + * @dev: i2c device handle + * + * + * + * LOCKING: + * Called from timer context + * + * RETURNS: + * EH_HANDLED or EH_NOT_HANDLED + */ +static int +tps65950_write(device_t dev, uint8_t addr, uint8_t *data, uint8_t size) +{ + uint8_t buffer[MAX_IIC_DATA_SIZE + 1]; + struct iic_msg msgs[1] = { + { TPS65950_ADDR, IIC_M_WR, size + 1, buffer }, + }; + + if (size > MAX_IIC_DATA_SIZE) + return (ENOMEM); + + buffer[0] = addr; + memcpy(buffer + 1, data, size); + + return (iicbus_transfer(dev, msgs, 1)); +} + +/** + * tps65950_init - attach function for the driver + * @dev: i2c device handle + * + * + * + * LOCKING: + * Called from timer context + * + * RETURNS: + * EH_HANDLED or EH_NOT_HANDLED + */ +static void +tps65950_init(void *arg) +{ + device_t dev = (device_t)arg; + struct tps65950_softc *sc = device_get_softc(dev); + uint8_t rsp = 0x00; + int error = 0; + + error = tps65950_read(dev, 0xEE, &rsp, 1); + printf("[BRG] Read 0x%02x from the tps65950 (error = %d)\n", rsp, error); + + rsp = 0x00; + error = tps65950_write(dev, 0xEE, &rsp, 1); + printf("[BRG] Read 0x%02x from the tps65950 (error = %d)\n", rsp, error); + + error = tps65950_read(dev, 0xEE, &rsp, 1); + printf("[BRG] Read 0x%02x from the tps65950 (error = %d)\n", rsp, error); + + /* this seems a bit weird, but we appear to have to remove this intrhook + * function manually. + */ + config_intrhook_disestablish(&sc->sc_ich); + + return; +} + +/** + * tps65950_attach - attach function for the driver + * @dev: i2c device handle + * + * + * + * LOCKING: + * Called from timer context + * + * RETURNS: + * EH_HANDLED or EH_NOT_HANDLED + */ +static int +tps65950_attach(device_t dev) +{ + struct tps65950_softc *sc; + + sc = device_get_softc(dev); + sc->sc_dev = dev; + + /* install a function to initialised */ + sc->sc_ich.ich_func = tps65950_init; + sc->sc_ich.ich_arg = dev; + config_intrhook_establish(&sc->sc_ich); + + return (0); +} + +static device_method_t tps65950_methods[] = { + DEVMETHOD(device_probe, tps65950_probe), + DEVMETHOD(device_attach, tps65950_attach), + + {0, 0}, +}; + +static driver_t tps65950_driver = { + "tps65950", + tps65950_methods, + sizeof(struct tps65950_softc), +}; +static devclass_t tps65950_devclass; + +DRIVER_MODULE(tps65950, iicbus, tps65950_driver, tps65950_devclass, 0, 0); +MODULE_VERSION(tps65950, 1); +MODULE_DEPEND(tps65950, iicbus, 1, 1, 1); + Index: sys/dev/usb/controller/ehci_omap3.c =================================================================== --- sys/dev/usb/controller/ehci_omap3.c (revision 0) +++ sys/dev/usb/controller/ehci_omap3.c (revision 0) @@ -0,0 +1,1190 @@ +/* + * Copyright (c) 2010 + * Ben Gray . + * All rights reserved. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Ben Gray. + * 4. The name of the company nor the name of the author may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY BEN GRAY ``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 BEN GRAY 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. + */ + +/** + * Driver for the High Speed USB EHCI module on the TI OMAP3530 SoC. + * + * WARNING: I've only tried this driver on a limited number of USB peripherals, + * it is still very raw and bound to have numerous bugs in it. + * + * + * This driver is based on the FreeBSD IXP4xx EHCI driver with a lot of the + * setup sequence coming from the Linux community and their EHCI driver for + * OMAP. Without these as a base I don't think I would have been able to get + * this driver working. + * + * The driver only contains the EHCI parts, the module also supports OHCI and + * USB on-the-go (OTG), currently neither are supported. + * + * CAUTION: This driver was written to run on the beaglebaord dev board, so I + * have made some assumptions about the type of PHY used and some of the other + * settings. Bare that in mind if you intend to use this driver on another + * platform. + * + * NOTE: This module uses a few different clocks, one being a 60Mhz clock for + * the TTL part of the module. This clock is derived from DPPL5 which must be + * configured prior to loading this driver - it is not configured by the + * bootloader. It took me a long time to figure this out, and caused much + * frustration. This PLL is now setup in the timer/clocks part of the BSP, + * check out the omap3_prcm_setup_dpll5() function in omap_prcm.c for more info. + * + */ + +/** + * HINTS + * + * The following hints control the way the driver sets up the H/W (checked out + * BEAGLEBOARD.hints for an example): + * + * hint.ehci.0.phy_reset + * If not zero the driver will attempt to reset the PHY by toggling a GPIO + * pin during EHCI initialisation. The pin to toggle is set by one of the + * following hints, a "-1" value means don't toggle. + * + * hint.ehci.0.phy_reset_gpio_0 + * hint.ehci.0.phy_reset_gpio_1 + * hint.ehci.0.phy_reset_gpio_2 + * See hint.ehci.0.phy_reset. + * + * hint.ehci.0.phy_mode_0 + * hint.ehci.0.phy_mode_1 + * hint.ehci.0.phy_mode_2 + * Tells the driver which mode to configure the port in, PHY, TLL or NONE. + * The possible values are; 0 = EHCI_HCD_OMAP3_MODE_UNKNOWN, + * 1 = EHCI_HCD_OMAP3_MODE_PHY and 2 = EHCI_HCD_OMAP3_MODE_TLL. + * + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_bus.h" + +#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 +#include + +#include +#include + +#include +#include +#include + + +/* TLL Register Set */ +#define TLL_SYSCONFIG_CACTIVITY (1UL << 8) +#define TLL_SYSCONFIG_SIDLE_SMART_IDLE (2UL << 3) +#define TLL_SYSCONFIG_SIDLE_NO_IDLE (1UL << 3) +#define TLL_SYSCONFIG_SIDLE_FORCED_IDLE (0UL << 3) +#define TLL_SYSCONFIG_ENAWAKEUP (1UL << 2) +#define TLL_SYSCONFIG_SOFTRESET (1UL << 1) +#define TLL_SYSCONFIG_AUTOIDLE (1UL << 0) + +#define TLL_SYSSTATUS_RESETDONE (1UL << 0) + +#define TLL_SHARED_CONF_USB_90D_DDR_EN (1UL << 6) +#define TLL_SHARED_CONF_USB_180D_SDR_EN (1UL << 5) +#define TLL_SHARED_CONF_USB_DIVRATIO_MASK (7UL << 2) +#define TLL_SHARED_CONF_USB_DIVRATIO_128 (7UL << 2) +#define TLL_SHARED_CONF_USB_DIVRATIO_64 (6UL << 2) +#define TLL_SHARED_CONF_USB_DIVRATIO_32 (5UL << 2) +#define TLL_SHARED_CONF_USB_DIVRATIO_16 (4UL << 2) +#define TLL_SHARED_CONF_USB_DIVRATIO_8 (3UL << 2) +#define TLL_SHARED_CONF_USB_DIVRATIO_4 (2UL << 2) +#define TLL_SHARED_CONF_USB_DIVRATIO_2 (1UL << 2) +#define TLL_SHARED_CONF_USB_DIVRATIO_1 (0UL << 2) +#define TLL_SHARED_CONF_FCLK_REQ (1UL << 1) +#define TLL_SHARED_CONF_FCLK_IS_ON (1UL << 0) + +#define TLL_CHANNEL_CONF_DRVVBUS (1UL << 16) +#define TLL_CHANNEL_CONF_CHRGVBUS (1UL << 15) +#define TLL_CHANNEL_CONF_ULPINOBITSTUFF (1UL << 11) +#define TLL_CHANNEL_CONF_ULPIAUTOIDLE (1UL << 10) +#define TLL_CHANNEL_CONF_UTMIAUTOIDLE (1UL << 9) +#define TLL_CHANNEL_CONF_ULPIDDRMODE (1UL << 8) +#define TLL_CHANNEL_CONF_ULPIOUTCLKMODE (1UL << 7) +#define TLL_CHANNEL_CONF_TLLFULLSPEED (1UL << 6) +#define TLL_CHANNEL_CONF_TLLCONNECT (1UL << 5) +#define TLL_CHANNEL_CONF_TLLATTACH (1UL << 4) +#define TLL_CHANNEL_CONF_UTMIISADEV (1UL << 3) +#define TLL_CHANNEL_CONF_CHANEN (1UL << 0) + + +/* UHH Register Set */ +#define UHH_SYSCONFIG_MIDLEMODE_MASK (3UL << 12) +#define UHH_SYSCONFIG_MIDLEMODE_SMARTSTANDBY (2UL << 12) +#define UHH_SYSCONFIG_MIDLEMODE_NOSTANDBY (1UL << 12) +#define UHH_SYSCONFIG_MIDLEMODE_FORCESTANDBY (0UL << 12) +#define UHH_SYSCONFIG_CLOCKACTIVITY (1UL << 8) +#define UHH_SYSCONFIG_SIDLEMODE_MASK (3UL << 3) +#define UHH_SYSCONFIG_SIDLEMODE_SMARTIDLE (2UL << 3) +#define UHH_SYSCONFIG_SIDLEMODE_NOIDLE (1UL << 3) +#define UHH_SYSCONFIG_SIDLEMODE_FORCEIDLE (0UL << 3) +#define UHH_SYSCONFIG_ENAWAKEUP (1UL << 2) +#define UHH_SYSCONFIG_SOFTRESET (1UL << 1) +#define UHH_SYSCONFIG_AUTOIDLE (1UL << 0) + +#define UHH_HOSTCONFIG_P3_CONNECT_STATUS (1UL << 10) +#define UHH_HOSTCONFIG_P2_CONNECT_STATUS (1UL << 9) +#define UHH_HOSTCONFIG_P1_CONNECT_STATUS (1UL << 8) +#define UHH_HOSTCONFIG_ENA_INCR_ALIGN (1UL << 5) +#define UHH_HOSTCONFIG_ENA_INCR16 (1UL << 4) +#define UHH_HOSTCONFIG_ENA_INCR8 (1UL << 3) +#define UHH_HOSTCONFIG_ENA_INCR4 (1UL << 2) +#define UHH_HOSTCONFIG_AUTOPPD_ON_OVERCUR_EN (1UL << 1) +#define UHH_HOSTCONFIG_P1_ULPI_BYPASS (1UL << 0) + + + + +#define EHCI_VENDORID_OMAP3 0x42fa05 +#define OMAP3_EHCI_HC_DEVSTR "Texas Instruments OMAP USB 2.0 controller" + +#define EHCI_HCD_OMAP3_MODE_UNKNOWN 0 +#define EHCI_HCD_OMAP3_MODE_PHY 1 +#define EHCI_HCD_OMAP3_MODE_TLL 2 + + + +struct omap3_ehci_softc { + ehci_softc_t base; /* storage for EHCI code */ + + device_t sc_dev; + + bus_space_tag_t sc_iotag_host; + bus_space_handle_t sc_ioh_host; + + struct resource* sc_res_tll; + bus_space_tag_t sc_iotag_tll; + bus_space_handle_t sc_ioh_tll; + + int port_mode[3]; + + int phy_reset; + int reset_gpio_pin[3]; +}; + +static device_attach_t ehci_omap3_attach; +static device_detach_t ehci_omap3_detach; +static device_shutdown_t ehci_omap3_shutdown; +static device_suspend_t ehci_omap3_suspend; +static device_resume_t ehci_omap3_resume; + +/** + * omap3_tll_readl - read a 32-bit value from the USBTLL registers + * omap3_tll_writel - write a 32-bit value from the USBTLL registers + * omap3_tll_readb - read an 8-bit value from the USBTLL registers + * omap3_tll_writeb - write an 8-bit value from the USBTLL registers + * @sc: omap3 ehci device context + * @off: byte offset within the register set to read from + * @val: the value to write into the register + * + * + * LOCKING: + * None + * + * RETURNS: + * nothing in case of write function, if read function returns the value read. + */ +static inline uint32_t +omap3_tll_readl(struct omap3_ehci_softc *sc, bus_size_t off) +{ + return bus_space_read_4(sc->sc_iotag_tll, sc->sc_ioh_tll, off); +} +static inline void +omap3_tll_writel(struct omap3_ehci_softc *sc, bus_size_t off, uint32_t val) +{ + bus_space_write_4(sc->sc_iotag_tll, sc->sc_ioh_tll, off, val); +} +static inline uint8_t +omap3_tll_readb(struct omap3_ehci_softc *sc, bus_size_t off) +{ + return bus_space_read_1(sc->sc_iotag_tll, sc->sc_ioh_tll, off); +} +static inline void +omap3_tll_writeb(struct omap3_ehci_softc *sc, bus_size_t off, uint8_t val) +{ + bus_space_write_1(sc->sc_iotag_tll, sc->sc_ioh_tll, off, val); +} + + +/** + * omap3_ehci_readl - read a 32-bit value from the UHH/OHCI/EHCI registers + * omap3_ehci_writel - write a 32-bit value from the UHH/OHCI/EHCI registers + * @sc: omap3 ehci device context + * @off: byte offset within the register set to read from + * @val: the value to write into the register + * + * + * LOCKING: + * None + * + * RETURNS: + * nothing in case of write function, if read function returns the value read. + */ +static inline uint32_t +omap3_ehci_readl(struct omap3_ehci_softc *sc, bus_size_t off) +{ + return bus_space_read_4(sc->sc_iotag_host, sc->sc_ioh_host, off); +} +static inline void +omap3_ehci_writel(struct omap3_ehci_softc *sc, bus_size_t off, uint32_t val) +{ + bus_space_write_4(sc->sc_iotag_host, sc->sc_ioh_host, off, val); +} + + + + + +/** + * ehci_omap3_utmi_init - initialises the UTMI part of the controller + * @isc: omap3 ehci device context + * + * + * + * LOCKING: + * none + * + * RETURNS: + * nothing + */ +static void +ehci_omap3_utmi_init(struct omap3_ehci_softc *isc, unsigned int en_mask) +{ + unsigned int i; + uint32_t reg; + + /* There are 3 TLL channels, one per USB controller so set them all up the + * same, SDR mode, bit stuffing and no autoidle. + */ + for (i=0; i<3; i++) { + reg = omap3_tll_readl(isc, OMAP35XX_USBTLL_TLL_CHANNEL_CONF(i)); + + reg &= ~(TLL_CHANNEL_CONF_UTMIAUTOIDLE + | TLL_CHANNEL_CONF_ULPINOBITSTUFF + | TLL_CHANNEL_CONF_ULPIDDRMODE); + + omap3_tll_writel(isc, OMAP35XX_USBTLL_TLL_CHANNEL_CONF(i), reg); + } + + /* Program the common TLL register */ + reg = omap3_tll_readl(isc, OMAP35XX_USBTLL_TLL_SHARED_CONF); + + reg &= ~( TLL_SHARED_CONF_USB_90D_DDR_EN + | TLL_SHARED_CONF_USB_DIVRATIO_MASK); + reg |= ( TLL_SHARED_CONF_FCLK_IS_ON + | TLL_SHARED_CONF_USB_DIVRATIO_2 + | TLL_SHARED_CONF_USB_180D_SDR_EN); + + omap3_tll_writel(isc, OMAP35XX_USBTLL_TLL_SHARED_CONF, reg); + + /* Enable channels now */ + for (i = 0; i < 3; i++) { + reg = omap3_tll_readl(isc, OMAP35XX_USBTLL_TLL_CHANNEL_CONF(i)); + + /* Enable only the reg that is needed */ + if ((en_mask & (1 << i)) == 0) + continue; + + reg |= TLL_CHANNEL_CONF_CHANEN; + omap3_tll_writel(isc, OMAP35XX_USBTLL_TLL_CHANNEL_CONF(i), reg); + } +} + + + + +/** + * ehci_omap3_init - initialises the USB host EHCI controller + * @isc: omap3 ehci device context + * + * This initialisation routine is quite heavily based on the work done by the + * OMAP Linux team (for which I thank them very much). The init sequence is + * almost identical, diverging only for the FreeBSD specifics. + * + * LOCKING: + * none + * + * RETURNS: + * 0 on success, a negative error code on failure. + */ +static int +ehci_omap3_init(struct omap3_ehci_softc *isc) +{ + unsigned long timeout; + int ret = 0; + uint8_t tll_ch_mask = 0; + uint32_t reg = 0; + + device_printf(isc->sc_dev, "Starting TI EHCI USB Controller\n"); + + + /* Enable Clocks for USBHOST */ + omap3_prcm_enable_clk(OMAP3_MODULE_USBHOST_ICLK); + omap3_prcm_enable_clk(OMAP3_MODULE_USBHOST_120M_FCLK); + omap3_prcm_enable_clk(OMAP3_MODULE_USBHOST_48M_FCLK); + + + + /* XXX: HACK to get USB working */ + isc->phy_reset = 1; + isc->reset_gpio_pin[1] = 147; +printf("===============> %d %d\n", isc->phy_reset, isc->reset_gpio_pin[1]); + /* Hold the PHY in reset while configuring */ + if (isc->phy_reset) { + + if (isc->reset_gpio_pin[0] != -1) { + /* Set the pad as a GPIO pin and output */ + omap3_scm_padconf_set_gpiomode(isc->reset_gpio_pin[0], + PADCONF_PIN_OUTPUT); + /* Configure the GPIO to drive low (hold in reset) */ + omap3_gpio_request(isc->reset_gpio_pin[0], "USB1 PHY reset"); + omap3_gpio_direction_output(isc->reset_gpio_pin[0], 0); + } + + if (isc->reset_gpio_pin[1] != -1) { + /* Set the pad as a GPIO pin and output */ + omap3_scm_padconf_set_gpiomode(isc->reset_gpio_pin[1], + PADCONF_PIN_OUTPUT); + /* Configure the GPIO to drive low (hold in reset) */ + omap3_gpio_request(isc->reset_gpio_pin[1], "USB2 PHY reset"); + omap3_gpio_direction_output(isc->reset_gpio_pin[1], 0); + } + + /* Hold the PHY in RESET for enough time till DIR is high */ + DELAY(10); + } + + + + /* Configure TLL for 60Mhz clk for ULPI. Note the 60Mhz clock comes from + * PLL5 which is not enabled by default at start-up. However in the clk + * driver (omap3_timer.c) it is specifcially enabled and set to 60Mhz. + */ + //omap3_prcm_enable_clk_ex(USBTTL_FCLK); + //omap3_prcm_enable_clk_ex(USBTTL_ICLK); + omap3_prcm_enable_clk(OMAP3_MODULE_USBTLL_FCLK); + omap3_prcm_enable_clk(OMAP3_MODULE_USBTLL_ICLK); + + /* Perform TLL soft reset, and wait until reset is complete */ + omap3_tll_writel(isc, OMAP35XX_USBTLL_SYSCONFIG, TLL_SYSCONFIG_SOFTRESET); + + /* Set the timeout to 100ms*/ + timeout = (hz < 10) ? 1 : ((100 * hz) / 1000); + + /* Wait for TLL reset to complete */ + while ((omap3_tll_readl(isc, OMAP35XX_USBTLL_SYSSTATUS) & TLL_SYSSTATUS_RESETDONE) == 0x00) { + + /* Sleep for a tick */ + pause("USBRESET", 1); + + if (timeout-- == 0) { + device_printf(isc->sc_dev, "TLL reset operation timed out\n"); + ret = -EINVAL; + goto err_sys_status; + } + } + + device_printf(isc->sc_dev, "TLL RESET DONE\n"); + + + /* + * CLOCKACTIVITY = 1 : OCP-derived internal clocks ON during idle + * SIDLEMODE = 2 : Smart-idle mode. Sidleack asserted after Idlereq + * assertion when no more activity on the USB. + * ENAWAKEUP = 1 : Wakeup generation enabled + */ + omap3_tll_writel(isc, OMAP35XX_USBTLL_SYSCONFIG, TLL_SYSCONFIG_ENAWAKEUP | + TLL_SYSCONFIG_AUTOIDLE | + TLL_SYSCONFIG_SIDLE_SMART_IDLE | + TLL_SYSCONFIG_CACTIVITY); + + /* Put UHH in SmartIdle/SmartStandby mode */ + reg = omap3_ehci_readl(isc, OMAP35XX_USBHOST_UHH_SYSCONFIG); + reg &= ~(UHH_SYSCONFIG_SIDLEMODE_MASK | + UHH_SYSCONFIG_MIDLEMODE_MASK); + reg |= (UHH_SYSCONFIG_ENAWAKEUP | + UHH_SYSCONFIG_AUTOIDLE | + UHH_SYSCONFIG_CLOCKACTIVITY | + UHH_SYSCONFIG_SIDLEMODE_SMARTIDLE | + UHH_SYSCONFIG_MIDLEMODE_SMARTSTANDBY); + omap3_ehci_writel(isc, OMAP35XX_USBHOST_UHH_SYSCONFIG, reg); + + + reg = omap3_ehci_readl(isc, OMAP35XX_USBHOST_UHH_HOSTCONFIG); + + /* Setup ULPI bypass and burst configurations */ + reg |= (UHH_HOSTCONFIG_ENA_INCR4 | + UHH_HOSTCONFIG_ENA_INCR8 | + UHH_HOSTCONFIG_ENA_INCR16); + reg &= ~UHH_HOSTCONFIG_ENA_INCR_ALIGN; + + if (isc->port_mode[0] == EHCI_HCD_OMAP3_MODE_UNKNOWN) + reg &= ~UHH_HOSTCONFIG_P1_CONNECT_STATUS; + if (isc->port_mode[1] == EHCI_HCD_OMAP3_MODE_UNKNOWN) + reg &= ~UHH_HOSTCONFIG_P2_CONNECT_STATUS; + if (isc->port_mode[2] == EHCI_HCD_OMAP3_MODE_UNKNOWN) + reg &= ~UHH_HOSTCONFIG_P3_CONNECT_STATUS; + + /* Bypass the TLL module for PHY mode operation */ + if ((isc->port_mode[0] == EHCI_HCD_OMAP3_MODE_PHY) || + (isc->port_mode[1] == EHCI_HCD_OMAP3_MODE_PHY) || + (isc->port_mode[2] == EHCI_HCD_OMAP3_MODE_PHY)) + reg &= ~UHH_HOSTCONFIG_P1_ULPI_BYPASS; + else + reg |= UHH_HOSTCONFIG_P1_ULPI_BYPASS; + + omap3_ehci_writel(isc, OMAP35XX_USBHOST_UHH_HOSTCONFIG, reg); + device_printf(isc->sc_dev, "UHH setup done, uhh_hostconfig=%x\n", reg); + + + /* If any of the ports are configured in TLL mode, enable them */ + if ((isc->port_mode[0] == EHCI_HCD_OMAP3_MODE_TLL) || + (isc->port_mode[1] == EHCI_HCD_OMAP3_MODE_TLL) || + (isc->port_mode[2] == EHCI_HCD_OMAP3_MODE_TLL)) { + + if (isc->port_mode[0] == EHCI_HCD_OMAP3_MODE_TLL) + tll_ch_mask |= 0x1; + if (isc->port_mode[1] == EHCI_HCD_OMAP3_MODE_TLL) + tll_ch_mask |= 0x2; + if (isc->port_mode[2] == EHCI_HCD_OMAP3_MODE_TLL) + tll_ch_mask |= 0x4; + + /* Enable UTMI mode for required TLL channels */ + ehci_omap3_utmi_init(isc, tll_ch_mask); + } + + +printf("===============> %d %d\n", isc->phy_reset, isc->reset_gpio_pin[1]); + /* Release the PHY reset signal now we have configured everything */ + if (isc->phy_reset) { + + /* Delay for 10ms */ + DELAY(10000); + + /* Release reset */ + if (isc->reset_gpio_pin[0] != -1) + omap3_gpio_pin_set(isc->reset_gpio_pin[0], 1); + + if (isc->reset_gpio_pin[1] != -1) { + omap3_gpio_pin_set(isc->reset_gpio_pin[1], 1); + } + } + + + /* Set the interrupt threshold control, it controls the maximum rate at + * which the host controller issues interrupts. We set it to 1 microframe + * at startup - the default is 8 mircoframes (equates to 1ms). + */ + reg = omap3_ehci_readl(isc, OMAP35XX_USBHOST_USBCMD); + reg &= 0xff00ffff; + reg |= (1 << 16); + omap3_ehci_writel(isc, OMAP35XX_USBHOST_USBCMD, reg); + + + return(0); + +err_sys_status: + + /* Disable the TLL clocks */ + omap3_prcm_disable_clk(OMAP3_MODULE_USBTLL_FCLK); + omap3_prcm_disable_clk(OMAP3_MODULE_USBTLL_ICLK); + + /* Free the reset lines GPIO */ + omap3_gpio_free(isc->reset_gpio_pin[0]); + omap3_gpio_free(isc->reset_gpio_pin[1]); + + /* Disable Clocks for USBHOST */ + omap3_prcm_disable_clk(OMAP3_MODULE_USBHOST_ICLK); + omap3_prcm_disable_clk(OMAP3_MODULE_USBHOST_120M_FCLK); + omap3_prcm_disable_clk(OMAP3_MODULE_USBHOST_48M_FCLK); + + return(ret); +} + + +/** + * ehci_omap3_fini - shutdown the EHCI controller + * @isc: omap3 ehci device context + * + * + * + * LOCKING: + * none + * + * RETURNS: + * 0 on success, a negative error code on failure. + */ +static void +ehci_omap3_fini(struct omap3_ehci_softc *isc) +{ + unsigned long timeout; + + device_printf(isc->sc_dev, "Stopping TI EHCI USB Controller\n"); + + /* Set the timeout */ + if (hz < 10) + timeout = 1; + else + timeout = (100 * hz) / 1000; + + /* Reset the UHH, OHCI and EHCI modules */ + omap3_ehci_writel(isc, OMAP35XX_USBHOST_UHH_SYSCONFIG, 0x0002); + while ((omap3_ehci_readl(isc, OMAP35XX_USBHOST_UHH_SYSSTATUS) & 0x07) == 0x00) { + /* Sleep for a tick */ + pause("USBRESET", 1); + + if (timeout-- == 0) { + device_printf(isc->sc_dev, "operation timed out\n"); + break; + } + } + + + /* Set the timeout */ + if (hz < 10) + timeout = 1; + else + timeout = (100 * hz) / 1000; + + /* Reset the TLL module */ + omap3_tll_writel(isc, OMAP35XX_USBTLL_SYSCONFIG, 0x0002); + while ((omap3_tll_readl(isc, OMAP35XX_USBTLL_SYSSTATUS) & (0x01)) == 0x00) { + /* Sleep for a tick */ + pause("USBRESET", 1); + + if (timeout-- == 0) { + device_printf(isc->sc_dev, "operation timed out\n"); + break; + } + } + + + /* Disable functional and interface clocks for the TLL and HOST modules */ + omap3_prcm_disable_clk(OMAP3_MODULE_USBTLL_FCLK); + + omap3_prcm_disable_clk(OMAP3_MODULE_USBHOST_ICLK); + omap3_prcm_disable_clk(OMAP3_MODULE_USBHOST_48M_FCLK); + omap3_prcm_disable_clk(OMAP3_MODULE_USBHOST_120M_FCLK); + + omap3_prcm_disable_clk(OMAP3_MODULE_USBTLL_ICLK); + + + /* Release the GPIO lines */ + if (isc->phy_reset) { + if (isc->reset_gpio_pin[0] != -1) + omap3_gpio_free(isc->reset_gpio_pin[0]); + + if (isc->reset_gpio_pin[1] != -1) + omap3_gpio_free(isc->reset_gpio_pin[1]); + } + + device_printf(isc->sc_dev, "Clock to USB host has been disabled\n"); + +} + + +/** + * ehci_omap3_conf_pinmux - configures the pinmux for the USB pins + * @isc: omap3 ehci driver context + * + * Configures the actual USB pins based on the configuration stored in the + * driver context. + * + * LOCKING: + * none + * + * RETURNS: + * always returns 0 (success) + */ +static int +ehci_omap3_conf_pinmux(struct omap3_ehci_softc *isc) +{ + switch (isc->port_mode[0]) { + case EHCI_HCD_OMAP3_MODE_PHY: + omap3_scm_padconf_set(CONTROL_PADCONF_ETK_CLK, 3, /* hsusb1_stp */ + PADCONF_PIN_OUTPUT); + omap3_scm_padconf_set(CONTROL_PADCONF_ETK_CTL, 3, /* hsusb1_clk */ + PADCONF_PIN_OUTPUT); + omap3_scm_padconf_set(CONTROL_PADCONF_ETK_D8, 3, /* hsusb1_dir */ + PADCONF_PIN_INPUT_PULLDOWN); + omap3_scm_padconf_set(CONTROL_PADCONF_ETK_D9, 3, /* hsusb1_clk */ + PADCONF_PIN_INPUT_PULLDOWN); + omap3_scm_padconf_set(CONTROL_PADCONF_ETK_D0, 3, /* hsusb1_nxt */ + PADCONF_PIN_INPUT_PULLDOWN); + omap3_scm_padconf_set(CONTROL_PADCONF_ETK_D1, 3, /* hsusb1_data0 */ + PADCONF_PIN_INPUT_PULLDOWN); + omap3_scm_padconf_set(CONTROL_PADCONF_ETK_D2, 3, /* hsusb1_data1 */ + PADCONF_PIN_INPUT_PULLDOWN); + omap3_scm_padconf_set(CONTROL_PADCONF_ETK_D3, 3, /* hsusb1_data2 */ + PADCONF_PIN_INPUT_PULLDOWN); + omap3_scm_padconf_set(CONTROL_PADCONF_ETK_D4, 3, /* hsusb1_data3 */ + PADCONF_PIN_INPUT_PULLDOWN); + omap3_scm_padconf_set(CONTROL_PADCONF_ETK_D5, 3, /* hsusb1_data4 */ + PADCONF_PIN_INPUT_PULLDOWN); + omap3_scm_padconf_set(CONTROL_PADCONF_ETK_D6, 3, /* hsusb1_data5 */ + PADCONF_PIN_INPUT_PULLDOWN); + omap3_scm_padconf_set(CONTROL_PADCONF_ETK_D7, 3, /* hsusb1_data6 */ + PADCONF_PIN_INPUT_PULLDOWN); + break; + case EHCI_HCD_OMAP3_MODE_TLL: + omap3_scm_padconf_set(CONTROL_PADCONF_ETK_CLK, 6, /* hsusb1_tll_stp */ + PADCONF_PIN_INPUT_PULLUP); + omap3_scm_padconf_set(CONTROL_PADCONF_ETK_CTL, 6, /* hsusb1_tll_clk */ + PADCONF_PIN_INPUT_PULLDOWN); + omap3_scm_padconf_set(CONTROL_PADCONF_ETK_D8, 6, /* hsusb1_tll_dir */ + PADCONF_PIN_INPUT_PULLDOWN); + omap3_scm_padconf_set(CONTROL_PADCONF_ETK_D9, 6, /* hsusb1_tll_nxt */ + PADCONF_PIN_INPUT_PULLDOWN); + omap3_scm_padconf_set(CONTROL_PADCONF_ETK_D0, 6, /* hsusb1_tll_data0 */ + PADCONF_PIN_INPUT_PULLDOWN); + omap3_scm_padconf_set(CONTROL_PADCONF_ETK_D1, 6, /* hsusb1_tll_data1 */ + PADCONF_PIN_INPUT_PULLDOWN); + omap3_scm_padconf_set(CONTROL_PADCONF_ETK_D2, 6, /* hsusb1_tll_data2 */ + PADCONF_PIN_INPUT_PULLDOWN); + omap3_scm_padconf_set(CONTROL_PADCONF_ETK_D3, 6, /* hsusb1_tll_data3 */ + PADCONF_PIN_INPUT_PULLDOWN); + omap3_scm_padconf_set(CONTROL_PADCONF_ETK_D4, 6, /* hsusb1_tll_data4 */ + PADCONF_PIN_INPUT_PULLDOWN); + omap3_scm_padconf_set(CONTROL_PADCONF_ETK_D5, 6, /* hsusb1_tll_data5 */ + PADCONF_PIN_INPUT_PULLDOWN); + omap3_scm_padconf_set(CONTROL_PADCONF_ETK_D6, 6, /* hsusb1_tll_data6 */ + PADCONF_PIN_INPUT_PULLDOWN); + omap3_scm_padconf_set(CONTROL_PADCONF_ETK_D7, 6, /* hsusb1_tll_data7 */ + PADCONF_PIN_INPUT_PULLDOWN); + break; + case EHCI_HCD_OMAP3_MODE_UNKNOWN: + /* FALLTHROUGH */ + default: + break; + } + + switch (isc->port_mode[1]) { + case EHCI_HCD_OMAP3_MODE_PHY: + omap3_scm_padconf_set(CONTROL_PADCONF_ETK_D11, 3, /* hsusb2_stp */ + PADCONF_PIN_OUTPUT); + omap3_scm_padconf_set(CONTROL_PADCONF_ETK_D10, 3, /* hsusb2_clk */ + PADCONF_PIN_OUTPUT); + omap3_scm_padconf_set(CONTROL_PADCONF_ETK_D12, 3, /* hsusb2_dir */ + PADCONF_PIN_INPUT_PULLDOWN); + omap3_scm_padconf_set(CONTROL_PADCONF_ETK_D13, 3, /* hsusb2_nxt */ + PADCONF_PIN_INPUT_PULLDOWN); + omap3_scm_padconf_set(CONTROL_PADCONF_ETK_D14, 3, /* hsusb2_data0 */ + PADCONF_PIN_INPUT_PULLDOWN); + omap3_scm_padconf_set(CONTROL_PADCONF_ETK_D15, 3, /* hsusb2_data1 */ + PADCONF_PIN_INPUT_PULLDOWN); + omap3_scm_padconf_set(CONTROL_PADCONF_MCSPI1_CS3, 3, /* hsusb2_data2 */ + PADCONF_PIN_INPUT_PULLDOWN); + omap3_scm_padconf_set(CONTROL_PADCONF_MCSPI2_CS1, 3, /* hsusb2_data3 */ + PADCONF_PIN_INPUT_PULLDOWN); + omap3_scm_padconf_set(CONTROL_PADCONF_MCSPI2_SIMO, 3, /* hsusb2_data4 */ + PADCONF_PIN_INPUT_PULLDOWN); + omap3_scm_padconf_set(CONTROL_PADCONF_MCSPI2_SOMI, 3, /* hsusb2_data5 */ + PADCONF_PIN_INPUT_PULLDOWN); + omap3_scm_padconf_set(CONTROL_PADCONF_MCSPI2_CS0, 3, /* hsusb2_data6 */ + PADCONF_PIN_INPUT_PULLDOWN); + omap3_scm_padconf_set(CONTROL_PADCONF_MCSPI2_CLK, 3, /* hsusb2_data7 */ + PADCONF_PIN_INPUT_PULLDOWN); + break; + case EHCI_HCD_OMAP3_MODE_TLL: + omap3_scm_padconf_set(CONTROL_PADCONF_ETK_D11, 6, /* hsusb2_tll_stp */ + PADCONF_PIN_INPUT_PULLUP); + omap3_scm_padconf_set(CONTROL_PADCONF_ETK_D10, 6, /* hsusb2_tll_clk */ + PADCONF_PIN_INPUT_PULLDOWN); + omap3_scm_padconf_set(CONTROL_PADCONF_ETK_D12, 6, /* hsusb2_tll_dir */ + PADCONF_PIN_INPUT_PULLDOWN); + omap3_scm_padconf_set(CONTROL_PADCONF_ETK_D13, 6, /* hsusb2_tll_nxt */ + PADCONF_PIN_INPUT_PULLDOWN); + omap3_scm_padconf_set(CONTROL_PADCONF_ETK_D14, 6, /* hsusb2_tll_data0 */ + PADCONF_PIN_INPUT_PULLDOWN); + omap3_scm_padconf_set(CONTROL_PADCONF_ETK_D15, 6, /* hsusb2_tll_data1 */ + PADCONF_PIN_INPUT_PULLDOWN); + omap3_scm_padconf_set(CONTROL_PADCONF_MCSPI1_CS3, 2, /* hsusb2_tll_data2 */ + PADCONF_PIN_INPUT_PULLDOWN); + omap3_scm_padconf_set(CONTROL_PADCONF_MCSPI2_CS1, 2, /* hsusb2_tll_data3 */ + PADCONF_PIN_INPUT_PULLDOWN); + omap3_scm_padconf_set(CONTROL_PADCONF_MCSPI2_SIMO, 2, /* hsusb2_tll_data4 */ + PADCONF_PIN_INPUT_PULLDOWN); + omap3_scm_padconf_set(CONTROL_PADCONF_MCSPI2_SOMI, 2, /* hsusb2_tll_data5 */ + PADCONF_PIN_INPUT_PULLDOWN); + omap3_scm_padconf_set(CONTROL_PADCONF_MCSPI2_CS0, 2, /* hsusb2_tll_data6 */ + PADCONF_PIN_INPUT_PULLDOWN); + omap3_scm_padconf_set(CONTROL_PADCONF_MCSPI2_CLK, 2, /* hsusb2_tll_data7 */ + PADCONF_PIN_INPUT_PULLDOWN); + break; + case EHCI_HCD_OMAP3_MODE_UNKNOWN: + /* FALLTHROUGH */ + default: + break; + } + + switch (isc->port_mode[2]) { + case EHCI_HCD_OMAP3_MODE_PHY: + device_printf(isc->sc_dev, "Port 3 can't be used in PHY mode\n"); + break; + case EHCI_HCD_OMAP3_MODE_TLL: + omap3_scm_padconf_set(CONTROL_PADCONF_MMC2_DAT5, 5, /* hsusb3_tll_stp */ + PADCONF_PIN_INPUT_PULLUP); + omap3_scm_padconf_set(CONTROL_PADCONF_UART1_CTS, 5, /* hsusb3_tll_clk */ + PADCONF_PIN_INPUT_PULLDOWN); + omap3_scm_padconf_set(CONTROL_PADCONF_MMC2_DAT6, 5, /* hsusb3_tll_dir */ + PADCONF_PIN_INPUT_PULLDOWN); + omap3_scm_padconf_set(CONTROL_PADCONF_MMC2_DAT7, 5, /* hsusb3_tll_nxt */ + PADCONF_PIN_INPUT_PULLDOWN); + omap3_scm_padconf_set(CONTROL_PADCONF_MCBSP4_DR, 5, /* hsusb3_tll_data0 */ + PADCONF_PIN_INPUT_PULLDOWN); + omap3_scm_padconf_set(CONTROL_PADCONF_MCBSP4_CLKX, 5, /* hsusb3_tll_data1 */ + PADCONF_PIN_INPUT_PULLDOWN); + omap3_scm_padconf_set(CONTROL_PADCONF_MCBSP4_DX, 5, /* hsusb3_tll_data2 */ + PADCONF_PIN_INPUT_PULLDOWN); + omap3_scm_padconf_set(CONTROL_PADCONF_MCBSP4_FSX, 5, /* hsusb3_tll_data3 */ + PADCONF_PIN_INPUT_PULLDOWN); + omap3_scm_padconf_set(CONTROL_PADCONF_MCBSP3_DX, 5, /* hsusb3_tll_data4 */ + PADCONF_PIN_INPUT_PULLDOWN); + omap3_scm_padconf_set(CONTROL_PADCONF_MCBSP3_DR, 5, /* hsusb3_tll_data5 */ + PADCONF_PIN_INPUT_PULLDOWN); + omap3_scm_padconf_set(CONTROL_PADCONF_MCBSP3_CLKX, 5, /* hsusb3_tll_data6 */ + PADCONF_PIN_INPUT_PULLDOWN); + omap3_scm_padconf_set(CONTROL_PADCONF_MCBSP3_FSX, 5, /* hsusb3_tll_data7 */ + PADCONF_PIN_INPUT_PULLDOWN); + break; + case EHCI_HCD_OMAP3_MODE_UNKNOWN: + /* FALLTHROUGH */ + default: + break; + } + + + return 0; +} + + +/** + * ehci_omap3_suspend - suspends the bus + * @dev: omap ehci device + * + * Effectively boilerplate EHCI suspend code. + * + * TODO: There is a lot more we could do here - i.e. force the controller into + * idle mode and disable all the clocks for start. + * + * LOCKING: + * none + * + * RETURNS: + * 0 on success or a positive error code + */ +static int +ehci_omap3_suspend(device_t dev) +{ + ehci_softc_t *sc = device_get_softc(dev); + int err; + + err = bus_generic_suspend(dev); + if (err) + return (err); + ehci_suspend(sc); + return (0); +} + + +/** + * ehci_omap3_resume - resumes a suspended bus + * @dev: omap ehci device + * + * Effectively boilerplate EHCI resume code. + * + * LOCKING: + * none + * + * RETURNS: + * 0 on success or a positive error code on failure + */ +static int +ehci_omap3_resume(device_t dev) +{ + ehci_softc_t *sc = device_get_softc(dev); + + ehci_resume(sc); + + bus_generic_resume(dev); + + return (0); +} + + +/** + * ehci_omap3_shutdown - starts the given command + * @dev: + * + * Effectively boilerplate EHCI shutdown code. + * + * LOCKING: + * none. + * + * RETURNS: + * 0 on success or a positive error code on failure + */ +static int +ehci_omap3_shutdown(device_t dev) +{ + ehci_softc_t *sc = device_get_softc(dev); + int err; + + err = bus_generic_shutdown(dev); + if (err) + return (err); + ehci_shutdown(sc); + + return (0); +} + + +/** + * ehci_omap3_probe - starts the given command + * @dev: + * + * Effectively boilerplate EHCI resume code. + * + * LOCKING: + * Caller should be holding the OMAP3_MMC lock. + * + * RETURNS: + * EH_HANDLED or EH_NOT_HANDLED + */ +static int +ehci_omap3_probe(device_t dev) +{ + device_set_desc(dev, OMAP3_EHCI_HC_DEVSTR); + + return (BUS_PROBE_DEFAULT); +} + +/** + * ehci_omap3_attach - driver entry point, sets up the ECHI controller/driver + * @dev: the new device handle + * + * Sets up bus spaces, interrupt handles, etc for the EHCI controller. It also + * parses the resource hints and calls ehci_omap3_init() to initialise the + * H/W. + * + * LOCKING: + * none + * + * RETURNS: + * 0 on success or a positive error code on failure. + */ +static int +ehci_omap3_attach(device_t dev) +{ + struct omap3_ehci_softc *isc = device_get_softc(dev); + ehci_softc_t *sc = &isc->base; + int err; + int rid; + int rval; + + /* initialise some bus fields */ + sc->sc_bus.parent = dev; + sc->sc_bus.devices = sc->sc_devices; + sc->sc_bus.devices_max = EHCI_MAX_DEVICES; + + /* save the device */ + isc->sc_dev = dev; + + /* get all DMA memory */ + if (usb_bus_mem_alloc_all(&sc->sc_bus, USB_GET_DMA_TAG(dev), + &ehci_iterate_hw_softc)) { + return (ENOMEM); + } + + + + /* Allocate bus resources for TLL, UHH and USBHOST */ + rid = 0; + sc->sc_io_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, + OMAP35XX_USBHOST_HWBASE, + OMAP35XX_USBHOST_HWBASE + OMAP35XX_USBHOST_SIZE, + OMAP35XX_USBHOST_SIZE, + RF_ACTIVE); + if (!sc->sc_io_res) { + device_printf(dev, "Error: could not map memory\n"); + goto error; + } + + /* Get the bus tag and handle so we can locally access the register set */ + isc->sc_iotag_host = rman_get_bustag(sc->sc_io_res); + isc->sc_ioh_host = rman_get_bushandle(sc->sc_io_res); + + + + /* Map in the USBTLL register set */ + isc->sc_iotag_tll = &omap3_bs_tag; + if (bus_space_map(isc->sc_iotag_tll, OMAP35XX_USBTLL_HWBASE, OMAP35XX_USBTLL_SIZE, + 0, &isc->sc_ioh_tll)) { + device_printf(dev, "Error: cannot map registers\n"); + goto error; + } + + /* Request an interrupt resource */ + rid = 0; + sc->sc_irq_res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, OMAP35XX_IRQ_EHCI, + OMAP35XX_IRQ_EHCI, 1, RF_ACTIVE); + if (sc->sc_irq_res == NULL) { + device_printf(dev, "Error: could not allocate irq\n"); + goto error; + } + + + + /* Add this device as a child of the USBus device */ + sc->sc_bus.bdev = device_add_child(dev, "usbus", -1); + if (!sc->sc_bus.bdev) { + device_printf(dev, "Error: could not add USB device\n"); + goto error; + } + device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus); + device_set_desc(sc->sc_bus.bdev, OMAP3_EHCI_HC_DEVSTR); + + /* Set the vendor name */ + sprintf(sc->sc_vendor, "Texas Instruments"); + + + /* Setup the interrupt */ + err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, + NULL, (driver_intr_t *)ehci_interrupt, sc, &sc->sc_intr_hdl); + if (err) { + device_printf(dev, "Error: could not setup irq, %d\n", err); + sc->sc_intr_hdl = NULL; + goto error; + } + + + /* Set the defaults for the hints */ + isc->phy_reset = 0; + isc->reset_gpio_pin[0] = isc->reset_gpio_pin[1] = isc->reset_gpio_pin[2] = -1; + isc->port_mode[0] = isc->port_mode[1] = isc->port_mode[2] = EHCI_HCD_OMAP3_MODE_UNKNOWN; + + /* Hints are used to define the PHY interface settings */ + if (resource_int_value("ehci", 0, "phy_reset", &rval) == 0) + isc->phy_reset = rval; + + if (isc->phy_reset) { + if (resource_int_value("ehci", 0, "phy_reset_gpio_0", &rval) == 0) + isc->reset_gpio_pin[0] = rval; + if (resource_int_value("ehci", 0, "phy_reset_gpio_1", &rval) == 0) + isc->reset_gpio_pin[1] = rval; + if (resource_int_value("ehci", 0, "phy_reset_gpio_2", &rval) == 0) + isc->reset_gpio_pin[2] = rval; + } + + if (resource_int_value("ehci", 0, "phy_mode_0", &rval) == 0) + isc->port_mode[0] = rval; + if (resource_int_value("ehci", 0, "phy_mode_1", &rval) == 0) + isc->port_mode[1] = rval; + if (resource_int_value("ehci", 0, "phy_mode_2", &rval) == 0) + isc->port_mode[2] = rval; + + + + /* Configure the pins for USB operations */ + err = ehci_omap3_conf_pinmux(isc); + if (err) { + device_printf(dev, "Error: failed to configure pins for USB, %d\n", err); + goto error; + } + + + /* Initialise the ECHI registers */ + err = ehci_omap3_init(isc); + if (err) { + device_printf(dev, "Error: could not setup OMAP3 EHCI, %d\n", err); + goto error; + } + + + /* OMAP EHCI host controller registers start at certain offset within + * the whole USB registers range, so create a subregion for the host + * mode configuration purposes. + */ + sc->sc_io_tag = rman_get_bustag(sc->sc_io_res); + sc->sc_io_size = 0x100; + + if (bus_space_subregion(sc->sc_io_tag, rman_get_bushandle(sc->sc_io_res), + OMAP35XX_USBHOST_HCCAPBASE, sc->sc_io_size, + &sc->sc_io_hdl) != 0) { + device_printf(dev, "Unable to subregion USB host registers"); + goto error; + } + + + /* Finally we are ready to kick off the ECHI host controller */ + err = ehci_init(sc); + if (err == 0) { + err = device_probe_and_attach(sc->sc_bus.bdev); + } + if (err) { + device_printf(dev, "Error: USB init failed err=%d\n", err); + goto error; + } + + return (0); + +error: + ehci_omap3_detach(dev); + return (ENXIO); +} + +/** + * ehci_omap3_detach - detach the device and cleanup the driver + * @dev: device handle + * + * Clean-up routine where everything initialised in ehci_omap3_attach is + * freed and cleaned up. This function calls ehci_omap3_fini() to shutdown + * the on-chip module. + * + * LOCKING: + * none + * + * RETURNS: + * Always returns 0 (success). + */ +static int +ehci_omap3_detach(device_t dev) +{ + struct omap3_ehci_softc *isc = device_get_softc(dev); + ehci_softc_t *sc = &isc->base; + device_t bdev; + int err; + + if (sc->sc_bus.bdev) { + bdev = sc->sc_bus.bdev; + device_detach(bdev); + device_delete_child(dev, bdev); + } + /* during module unload there are lots of children leftover */ + device_delete_all_children(dev); + + /* + * disable interrupts that might have been switched on in ehci_init + */ + if (sc->sc_io_res) { + EWRITE4(sc, EHCI_USBINTR, 0); + } + + if (sc->sc_irq_res && sc->sc_intr_hdl) { + /* + * only call ehci_detach() after ehci_init() + */ + ehci_detach(sc); + + err = bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_intr_hdl); + if (err) + device_printf(dev, "Error: could not tear down irq, %d\n", err); + sc->sc_intr_hdl = NULL; + } + + if (sc->sc_irq_res) { + bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res); + sc->sc_irq_res = NULL; + } + if (sc->sc_io_res) { + bus_release_resource(dev, SYS_RES_MEMORY, 0, + sc->sc_io_res); + sc->sc_io_res = NULL; + } + usb_bus_mem_free_all(&sc->sc_bus, &ehci_iterate_hw_softc); + + ehci_omap3_fini(isc); + + return (0); +} + +static device_method_t ehci_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, ehci_omap3_probe), + DEVMETHOD(device_attach, ehci_omap3_attach), + DEVMETHOD(device_detach, ehci_omap3_detach), + DEVMETHOD(device_suspend, ehci_omap3_suspend), + DEVMETHOD(device_resume, ehci_omap3_resume), + DEVMETHOD(device_shutdown, ehci_omap3_shutdown), + + /* Bus interface */ + DEVMETHOD(bus_print_child, bus_generic_print_child), + + {0, 0} +}; + +static driver_t ehci_driver = { + "ehci", + ehci_methods, + sizeof(struct omap3_ehci_softc), +}; + +static devclass_t ehci_devclass; + +DRIVER_MODULE(ehci, omap3, ehci_driver, ehci_devclass, 0, 0); +MODULE_DEPEND(ehci, usb, 1, 1, 1); + +MODULE_DEPEND(ehci, omap3_prcm, 1, 1, 1); +MODULE_DEPEND(ehci, omap3_scm, 1, 1, 1); +MODULE_DEPEND(ehci, omap3_gpio, 1, 1, 1);