diff --git a/lib/libc/arm/string/memcpy.S b/lib/libc/arm/string/memcpy.S index 150533b67112..3628652681e0 100644 --- a/lib/libc/arm/string/memcpy.S +++ b/lib/libc/arm/string/memcpy.S @@ -2,4 +2,8 @@ #include __FBSDID("$FreeBSD$"); +#if !defined(_ARM_ARCH_5E) || defined(_STANDALONE) #include "memcpy_arm.S" +#else +#include "memcpy_xscale.S" +#endif diff --git a/lib/libc/arm/string/memcpy_xscale.S b/lib/libc/arm/string/memcpy_xscale.S new file mode 100644 index 000000000000..ab01544fc176 --- /dev/null +++ b/lib/libc/arm/string/memcpy_xscale.S @@ -0,0 +1,1788 @@ +/* $NetBSD: memcpy_xscale.S,v 1.1 2003/10/14 07:51:45 scw Exp $ */ + +/* + * Copyright 2003 Wasabi Systems, Inc. + * All rights reserved. + * + * Written by Steve C. Woodford 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. + */ + +#include +__FBSDID("$FreeBSD$"); + +.syntax unified + +/* LINTSTUB: Func: void *memcpy(void *dst, const void *src, size_t len) */ +ENTRY(memcpy) + pld [r1] + cmp r2, #0x0c + ble .Lmemcpy_short /* <= 12 bytes */ + mov r3, r0 /* We must not clobber r0 */ + + /* Word-align the destination buffer */ + ands ip, r3, #0x03 /* Already word aligned? */ + beq .Lmemcpy_wordaligned /* Yup */ + cmp ip, #0x02 + ldrb ip, [r1], #0x01 + sub r2, r2, #0x01 + strb ip, [r3], #0x01 + ldrble ip, [r1], #0x01 + suble r2, r2, #0x01 + strble ip, [r3], #0x01 + ldrblt ip, [r1], #0x01 + sublt r2, r2, #0x01 + strblt ip, [r3], #0x01 + + /* Destination buffer is now word aligned */ +.Lmemcpy_wordaligned: + ands ip, r1, #0x03 /* Is src also word-aligned? */ + bne .Lmemcpy_bad_align /* Nope. Things just got bad */ + + /* Quad-align the destination buffer */ + tst r3, #0x07 /* Already quad aligned? */ + ldrne ip, [r1], #0x04 + stmfd sp!, {r4-r9} /* Free up some registers */ + subne r2, r2, #0x04 + strne ip, [r3], #0x04 + + /* Destination buffer quad aligned, source is at least word aligned */ + subs r2, r2, #0x80 + blt .Lmemcpy_w_lessthan128 + + /* Copy 128 bytes at a time */ +.Lmemcpy_w_loop128: + ldr r4, [r1], #0x04 /* LD:00-03 */ + ldr r5, [r1], #0x04 /* LD:04-07 */ + pld [r1, #0x18] /* Prefetch 0x20 */ + ldr r6, [r1], #0x04 /* LD:08-0b */ + ldr r7, [r1], #0x04 /* LD:0c-0f */ + ldr r8, [r1], #0x04 /* LD:10-13 */ + ldr r9, [r1], #0x04 /* LD:14-17 */ + strd r4, [r3], #0x08 /* ST:00-07 */ + ldr r4, [r1], #0x04 /* LD:18-1b */ + ldr r5, [r1], #0x04 /* LD:1c-1f */ + strd r6, [r3], #0x08 /* ST:08-0f */ + ldr r6, [r1], #0x04 /* LD:20-23 */ + ldr r7, [r1], #0x04 /* LD:24-27 */ + pld [r1, #0x18] /* Prefetch 0x40 */ + strd r8, [r3], #0x08 /* ST:10-17 */ + ldr r8, [r1], #0x04 /* LD:28-2b */ + ldr r9, [r1], #0x04 /* LD:2c-2f */ + strd r4, [r3], #0x08 /* ST:18-1f */ + ldr r4, [r1], #0x04 /* LD:30-33 */ + ldr r5, [r1], #0x04 /* LD:34-37 */ + strd r6, [r3], #0x08 /* ST:20-27 */ + ldr r6, [r1], #0x04 /* LD:38-3b */ + ldr r7, [r1], #0x04 /* LD:3c-3f */ + strd r8, [r3], #0x08 /* ST:28-2f */ + ldr r8, [r1], #0x04 /* LD:40-43 */ + ldr r9, [r1], #0x04 /* LD:44-47 */ + pld [r1, #0x18] /* Prefetch 0x60 */ + strd r4, [r3], #0x08 /* ST:30-37 */ + ldr r4, [r1], #0x04 /* LD:48-4b */ + ldr r5, [r1], #0x04 /* LD:4c-4f */ + strd r6, [r3], #0x08 /* ST:38-3f */ + ldr r6, [r1], #0x04 /* LD:50-53 */ + ldr r7, [r1], #0x04 /* LD:54-57 */ + strd r8, [r3], #0x08 /* ST:40-47 */ + ldr r8, [r1], #0x04 /* LD:58-5b */ + ldr r9, [r1], #0x04 /* LD:5c-5f */ + strd r4, [r3], #0x08 /* ST:48-4f */ + ldr r4, [r1], #0x04 /* LD:60-63 */ + ldr r5, [r1], #0x04 /* LD:64-67 */ + pld [r1, #0x18] /* Prefetch 0x80 */ + strd r6, [r3], #0x08 /* ST:50-57 */ + ldr r6, [r1], #0x04 /* LD:68-6b */ + ldr r7, [r1], #0x04 /* LD:6c-6f */ + strd r8, [r3], #0x08 /* ST:58-5f */ + ldr r8, [r1], #0x04 /* LD:70-73 */ + ldr r9, [r1], #0x04 /* LD:74-77 */ + strd r4, [r3], #0x08 /* ST:60-67 */ + ldr r4, [r1], #0x04 /* LD:78-7b */ + ldr r5, [r1], #0x04 /* LD:7c-7f */ + strd r6, [r3], #0x08 /* ST:68-6f */ + strd r8, [r3], #0x08 /* ST:70-77 */ + subs r2, r2, #0x80 + strd r4, [r3], #0x08 /* ST:78-7f */ + bge .Lmemcpy_w_loop128 + +.Lmemcpy_w_lessthan128: + adds r2, r2, #0x80 /* Adjust for extra sub */ + ldmfdeq sp!, {r4-r9} + bxeq lr /* Return now if done */ + subs r2, r2, #0x20 + blt .Lmemcpy_w_lessthan32 + + /* Copy 32 bytes at a time */ +.Lmemcpy_w_loop32: + ldr r4, [r1], #0x04 + ldr r5, [r1], #0x04 + pld [r1, #0x18] + ldr r6, [r1], #0x04 + ldr r7, [r1], #0x04 + ldr r8, [r1], #0x04 + ldr r9, [r1], #0x04 + strd r4, [r3], #0x08 + ldr r4, [r1], #0x04 + ldr r5, [r1], #0x04 + strd r6, [r3], #0x08 + strd r8, [r3], #0x08 + subs r2, r2, #0x20 + strd r4, [r3], #0x08 + bge .Lmemcpy_w_loop32 + +.Lmemcpy_w_lessthan32: + adds r2, r2, #0x20 /* Adjust for extra sub */ + ldmfdeq sp!, {r4-r9} + bxeq lr /* Return now if done */ + + and r4, r2, #0x18 + rsbs r4, r4, #0x18 + addne pc, pc, r4, lsl #1 + nop + + /* At least 24 bytes remaining */ + ldr r4, [r1], #0x04 + ldr r5, [r1], #0x04 + sub r2, r2, #0x08 + strd r4, [r3], #0x08 + + /* At least 16 bytes remaining */ + ldr r4, [r1], #0x04 + ldr r5, [r1], #0x04 + sub r2, r2, #0x08 + strd r4, [r3], #0x08 + + /* At least 8 bytes remaining */ + ldr r4, [r1], #0x04 + ldr r5, [r1], #0x04 + subs r2, r2, #0x08 + strd r4, [r3], #0x08 + + /* Less than 8 bytes remaining */ + ldmfd sp!, {r4-r9} + bxeq lr /* Return now if done */ + subs r2, r2, #0x04 + ldrge ip, [r1], #0x04 + strge ip, [r3], #0x04 + bxeq lr /* Return now if done */ + addlt r2, r2, #0x04 + ldrb ip, [r1], #0x01 + cmp r2, #0x02 + ldrbge r2, [r1], #0x01 + strb ip, [r3], #0x01 + ldrbgt ip, [r1] + strbge r2, [r3], #0x01 + strbgt ip, [r3] + bx lr + + +/* + * At this point, it has not been possible to word align both buffers. + * The destination buffer is word aligned, but the source buffer is not. + */ +.Lmemcpy_bad_align: + stmfd sp!, {r4-r7} + bic r1, r1, #0x03 + cmp ip, #2 + ldr ip, [r1], #0x04 + bgt .Lmemcpy_bad3 + beq .Lmemcpy_bad2 + b .Lmemcpy_bad1 + +.Lmemcpy_bad1_loop16: +#ifdef __ARMEB__ + mov r4, ip, lsl #8 +#else + mov r4, ip, lsr #8 +#endif + ldr r5, [r1], #0x04 + pld [r1, #0x018] + ldr r6, [r1], #0x04 + ldr r7, [r1], #0x04 + ldr ip, [r1], #0x04 +#ifdef __ARMEB__ + orr r4, r4, r5, lsr #24 + mov r5, r5, lsl #8 + orr r5, r5, r6, lsr #24 + mov r6, r6, lsl #8 + orr r6, r6, r7, lsr #24 + mov r7, r7, lsl #8 + orr r7, r7, ip, lsr #24 +#else + orr r4, r4, r5, lsl #24 + mov r5, r5, lsr #8 + orr r5, r5, r6, lsl #24 + mov r6, r6, lsr #8 + orr r6, r6, r7, lsl #24 + mov r7, r7, lsr #8 + orr r7, r7, ip, lsl #24 +#endif + str r4, [r3], #0x04 + str r5, [r3], #0x04 + str r6, [r3], #0x04 + str r7, [r3], #0x04 +.Lmemcpy_bad1: + subs r2, r2, #0x10 + bge .Lmemcpy_bad1_loop16 + + adds r2, r2, #0x10 + ldmfdeq sp!, {r4-r7} + bxeq lr /* Return now if done */ + subs r2, r2, #0x04 + sublt r1, r1, #0x03 + blt .Lmemcpy_bad_done + +.Lmemcpy_bad1_loop4: +#ifdef __ARMEB__ + mov r4, ip, lsl #8 +#else + mov r4, ip, lsr #8 +#endif + ldr ip, [r1], #0x04 + subs r2, r2, #0x04 +#ifdef __ARMEB__ + orr r4, r4, ip, lsr #24 +#else + orr r4, r4, ip, lsl #24 +#endif + str r4, [r3], #0x04 + bge .Lmemcpy_bad1_loop4 + sub r1, r1, #0x03 + b .Lmemcpy_bad_done + +.Lmemcpy_bad2_loop16: +#ifdef __ARMEB__ + mov r4, ip, lsl #16 +#else + mov r4, ip, lsr #16 +#endif + ldr r5, [r1], #0x04 + pld [r1, #0x018] + ldr r6, [r1], #0x04 + ldr r7, [r1], #0x04 + ldr ip, [r1], #0x04 +#ifdef __ARMEB__ + orr r4, r4, r5, lsr #16 + mov r5, r5, lsl #16 + orr r5, r5, r6, lsr #16 + mov r6, r6, lsl #16 + orr r6, r6, r7, lsr #16 + mov r7, r7, lsl #16 + orr r7, r7, ip, lsr #16 +#else + orr r4, r4, r5, lsl #16 + mov r5, r5, lsr #16 + orr r5, r5, r6, lsl #16 + mov r6, r6, lsr #16 + orr r6, r6, r7, lsl #16 + mov r7, r7, lsr #16 + orr r7, r7, ip, lsl #16 +#endif + str r4, [r3], #0x04 + str r5, [r3], #0x04 + str r6, [r3], #0x04 + str r7, [r3], #0x04 +.Lmemcpy_bad2: + subs r2, r2, #0x10 + bge .Lmemcpy_bad2_loop16 + + adds r2, r2, #0x10 + ldmfdeq sp!, {r4-r7} + bxeq lr /* Return now if done */ + subs r2, r2, #0x04 + sublt r1, r1, #0x02 + blt .Lmemcpy_bad_done + +.Lmemcpy_bad2_loop4: +#ifdef __ARMEB__ + mov r4, ip, lsl #16 +#else + mov r4, ip, lsr #16 +#endif + ldr ip, [r1], #0x04 + subs r2, r2, #0x04 +#ifdef __ARMEB__ + orr r4, r4, ip, lsr #16 +#else + orr r4, r4, ip, lsl #16 +#endif + str r4, [r3], #0x04 + bge .Lmemcpy_bad2_loop4 + sub r1, r1, #0x02 + b .Lmemcpy_bad_done + +.Lmemcpy_bad3_loop16: +#ifdef __ARMEB__ + mov r4, ip, lsl #24 +#else + mov r4, ip, lsr #24 +#endif + ldr r5, [r1], #0x04 + pld [r1, #0x018] + ldr r6, [r1], #0x04 + ldr r7, [r1], #0x04 + ldr ip, [r1], #0x04 +#ifdef __ARMEB__ + orr r4, r4, r5, lsr #8 + mov r5, r5, lsl #24 + orr r5, r5, r6, lsr #8 + mov r6, r6, lsl #24 + orr r6, r6, r7, lsr #8 + mov r7, r7, lsl #24 + orr r7, r7, ip, lsr #8 +#else + orr r4, r4, r5, lsl #8 + mov r5, r5, lsr #24 + orr r5, r5, r6, lsl #8 + mov r6, r6, lsr #24 + orr r6, r6, r7, lsl #8 + mov r7, r7, lsr #24 + orr r7, r7, ip, lsl #8 +#endif + str r4, [r3], #0x04 + str r5, [r3], #0x04 + str r6, [r3], #0x04 + str r7, [r3], #0x04 +.Lmemcpy_bad3: + subs r2, r2, #0x10 + bge .Lmemcpy_bad3_loop16 + + adds r2, r2, #0x10 + ldmfdeq sp!, {r4-r7} + bxeq lr /* Return now if done */ + subs r2, r2, #0x04 + sublt r1, r1, #0x01 + blt .Lmemcpy_bad_done + +.Lmemcpy_bad3_loop4: +#ifdef __ARMEB__ + mov r4, ip, lsl #24 +#else + mov r4, ip, lsr #24 +#endif + ldr ip, [r1], #0x04 + subs r2, r2, #0x04 +#ifdef __ARMEB__ + orr r4, r4, ip, lsr #8 +#else + orr r4, r4, ip, lsl #8 +#endif + str r4, [r3], #0x04 + bge .Lmemcpy_bad3_loop4 + sub r1, r1, #0x01 + +.Lmemcpy_bad_done: + ldmfd sp!, {r4-r7} + adds r2, r2, #0x04 + bxeq lr + ldrb ip, [r1], #0x01 + cmp r2, #0x02 + ldrbge r2, [r1], #0x01 + strb ip, [r3], #0x01 + ldrbgt ip, [r1] + strbge r2, [r3], #0x01 + strbgt ip, [r3] + bx lr + + +/* + * Handle short copies (less than 16 bytes), possibly misaligned. + * Some of these are *very* common, thanks to the network stack, + * and so are handled specially. + */ +.Lmemcpy_short: +#ifndef _STANDALONE + add pc, pc, r2, lsl #2 + nop + bx lr /* 0x00 */ + b .Lmemcpy_bytewise /* 0x01 */ + b .Lmemcpy_bytewise /* 0x02 */ + b .Lmemcpy_bytewise /* 0x03 */ + b .Lmemcpy_4 /* 0x04 */ + b .Lmemcpy_bytewise /* 0x05 */ + b .Lmemcpy_6 /* 0x06 */ + b .Lmemcpy_bytewise /* 0x07 */ + b .Lmemcpy_8 /* 0x08 */ + b .Lmemcpy_bytewise /* 0x09 */ + b .Lmemcpy_bytewise /* 0x0a */ + b .Lmemcpy_bytewise /* 0x0b */ + b .Lmemcpy_c /* 0x0c */ +#endif +.Lmemcpy_bytewise: + mov r3, r0 /* We must not clobber r0 */ + ldrb ip, [r1], #0x01 +1: subs r2, r2, #0x01 + strb ip, [r3], #0x01 + ldrbne ip, [r1], #0x01 + bne 1b + bx lr + +#ifndef _STANDALONE +/****************************************************************************** + * Special case for 4 byte copies + */ +#define LMEMCPY_4_LOG2 6 /* 64 bytes */ +#define LMEMCPY_4_PAD .align LMEMCPY_4_LOG2 + LMEMCPY_4_PAD +.Lmemcpy_4: + and r2, r1, #0x03 + orr r2, r2, r0, lsl #2 + ands r2, r2, #0x0f + sub r3, pc, #0x14 + addne pc, r3, r2, lsl #LMEMCPY_4_LOG2 + +/* + * 0000: dst is 32-bit aligned, src is 32-bit aligned + */ + ldr r2, [r1] + str r2, [r0] + bx lr + LMEMCPY_4_PAD + +/* + * 0001: dst is 32-bit aligned, src is 8-bit aligned + */ + ldr r3, [r1, #-1] /* BE:r3 = x012 LE:r3 = 210x */ + ldr r2, [r1, #3] /* BE:r2 = 3xxx LE:r2 = xxx3 */ +#ifdef __ARMEB__ + mov r3, r3, lsl #8 /* r3 = 012. */ + orr r3, r3, r2, lsr #24 /* r3 = 0123 */ +#else + mov r3, r3, lsr #8 /* r3 = .210 */ + orr r3, r3, r2, lsl #24 /* r3 = 3210 */ +#endif + str r3, [r0] + bx lr + LMEMCPY_4_PAD + +/* + * 0010: dst is 32-bit aligned, src is 16-bit aligned + */ +#ifdef __ARMEB__ + ldrh r3, [r1] + ldrh r2, [r1, #0x02] +#else + ldrh r3, [r1, #0x02] + ldrh r2, [r1] +#endif + orr r3, r2, r3, lsl #16 + str r3, [r0] + bx lr + LMEMCPY_4_PAD + +/* + * 0011: dst is 32-bit aligned, src is 8-bit aligned + */ + ldr r3, [r1, #-3] /* BE:r3 = xxx0 LE:r3 = 0xxx */ + ldr r2, [r1, #1] /* BE:r2 = 123x LE:r2 = x321 */ +#ifdef __ARMEB__ + mov r3, r3, lsl #24 /* r3 = 0... */ + orr r3, r3, r2, lsr #8 /* r3 = 0123 */ +#else + mov r3, r3, lsr #24 /* r3 = ...0 */ + orr r3, r3, r2, lsl #8 /* r3 = 3210 */ +#endif + str r3, [r0] + bx lr + LMEMCPY_4_PAD + +/* + * 0100: dst is 8-bit aligned, src is 32-bit aligned + */ + ldr r2, [r1] +#ifdef __ARMEB__ + strb r2, [r0, #0x03] + mov r3, r2, lsr #8 + mov r1, r2, lsr #24 + strb r1, [r0] +#else + strb r2, [r0] + mov r3, r2, lsr #8 + mov r1, r2, lsr #24 + strb r1, [r0, #0x03] +#endif + strh r3, [r0, #0x01] + bx lr + LMEMCPY_4_PAD + +/* + * 0101: dst is 8-bit aligned, src is 8-bit aligned + */ + ldrb r2, [r1] + ldrh r3, [r1, #0x01] + ldrb r1, [r1, #0x03] + strb r2, [r0] + strh r3, [r0, #0x01] + strb r1, [r0, #0x03] + bx lr + LMEMCPY_4_PAD + +/* + * 0110: dst is 8-bit aligned, src is 16-bit aligned + */ + ldrh r2, [r1] /* BE:r2 = ..01 LE:r2 = ..10 */ + ldrh r3, [r1, #0x02] /* LE:r3 = ..23 LE:r3 = ..32 */ +#ifdef __ARMEB__ + mov r1, r2, lsr #8 /* r1 = ...0 */ + strb r1, [r0] + mov r2, r2, lsl #8 /* r2 = .01. */ + orr r2, r2, r3, lsr #8 /* r2 = .012 */ +#else + strb r2, [r0] + mov r2, r2, lsr #8 /* r2 = ...1 */ + orr r2, r2, r3, lsl #8 /* r2 = .321 */ + mov r3, r3, lsr #8 /* r3 = ...3 */ +#endif + strh r2, [r0, #0x01] + strb r3, [r0, #0x03] + bx lr + LMEMCPY_4_PAD + +/* + * 0111: dst is 8-bit aligned, src is 8-bit aligned + */ + ldrb r2, [r1] + ldrh r3, [r1, #0x01] + ldrb r1, [r1, #0x03] + strb r2, [r0] + strh r3, [r0, #0x01] + strb r1, [r0, #0x03] + bx lr + LMEMCPY_4_PAD + +/* + * 1000: dst is 16-bit aligned, src is 32-bit aligned + */ + ldr r2, [r1] +#ifdef __ARMEB__ + strh r2, [r0, #0x02] + mov r3, r2, lsr #16 + strh r3, [r0] +#else + strh r2, [r0] + mov r3, r2, lsr #16 + strh r3, [r0, #0x02] +#endif + bx lr + LMEMCPY_4_PAD + +/* + * 1001: dst is 16-bit aligned, src is 8-bit aligned + */ + ldr r2, [r1, #-1] /* BE:r2 = x012 LE:r2 = 210x */ + ldr r3, [r1, #3] /* BE:r3 = 3xxx LE:r3 = xxx3 */ + mov r1, r2, lsr #8 /* BE:r1 = .x01 LE:r1 = .210 */ + strh r1, [r0] +#ifdef __ARMEB__ + mov r2, r2, lsl #8 /* r2 = 012. */ + orr r2, r2, r3, lsr #24 /* r2 = 0123 */ +#else + mov r2, r2, lsr #24 /* r2 = ...2 */ + orr r2, r2, r3, lsl #8 /* r2 = xx32 */ +#endif + strh r2, [r0, #0x02] + bx lr + LMEMCPY_4_PAD + +/* + * 1010: dst is 16-bit aligned, src is 16-bit aligned + */ + ldrh r2, [r1] + ldrh r3, [r1, #0x02] + strh r2, [r0] + strh r3, [r0, #0x02] + bx lr + LMEMCPY_4_PAD + +/* + * 1011: dst is 16-bit aligned, src is 8-bit aligned + */ + ldr r3, [r1, #1] /* BE:r3 = 123x LE:r3 = x321 */ + ldr r2, [r1, #-3] /* BE:r2 = xxx0 LE:r2 = 0xxx */ + mov r1, r3, lsr #8 /* BE:r1 = .123 LE:r1 = .x32 */ + strh r1, [r0, #0x02] +#ifdef __ARMEB__ + mov r3, r3, lsr #24 /* r3 = ...1 */ + orr r3, r3, r2, lsl #8 /* r3 = xx01 */ +#else + mov r3, r3, lsl #8 /* r3 = 321. */ + orr r3, r3, r2, lsr #24 /* r3 = 3210 */ +#endif + strh r3, [r0] + bx lr + LMEMCPY_4_PAD + +/* + * 1100: dst is 8-bit aligned, src is 32-bit aligned + */ + ldr r2, [r1] /* BE:r2 = 0123 LE:r2 = 3210 */ +#ifdef __ARMEB__ + strb r2, [r0, #0x03] + mov r3, r2, lsr #8 + mov r1, r2, lsr #24 + strh r3, [r0, #0x01] + strb r1, [r0] +#else + strb r2, [r0] + mov r3, r2, lsr #8 + mov r1, r2, lsr #24 + strh r3, [r0, #0x01] + strb r1, [r0, #0x03] +#endif + bx lr + LMEMCPY_4_PAD + +/* + * 1101: dst is 8-bit aligned, src is 8-bit aligned + */ + ldrb r2, [r1] + ldrh r3, [r1, #0x01] + ldrb r1, [r1, #0x03] + strb r2, [r0] + strh r3, [r0, #0x01] + strb r1, [r0, #0x03] + bx lr + LMEMCPY_4_PAD + +/* + * 1110: dst is 8-bit aligned, src is 16-bit aligned + */ +#ifdef __ARMEB__ + ldrh r3, [r1, #0x02] /* BE:r3 = ..23 LE:r3 = ..32 */ + ldrh r2, [r1] /* BE:r2 = ..01 LE:r2 = ..10 */ + strb r3, [r0, #0x03] + mov r3, r3, lsr #8 /* r3 = ...2 */ + orr r3, r3, r2, lsl #8 /* r3 = ..12 */ + strh r3, [r0, #0x01] + mov r2, r2, lsr #8 /* r2 = ...0 */ + strb r2, [r0] +#else + ldrh r2, [r1] /* BE:r2 = ..01 LE:r2 = ..10 */ + ldrh r3, [r1, #0x02] /* BE:r3 = ..23 LE:r3 = ..32 */ + strb r2, [r0] + mov r2, r2, lsr #8 /* r2 = ...1 */ + orr r2, r2, r3, lsl #8 /* r2 = .321 */ + strh r2, [r0, #0x01] + mov r3, r3, lsr #8 /* r3 = ...3 */ + strb r3, [r0, #0x03] +#endif + bx lr + LMEMCPY_4_PAD + +/* + * 1111: dst is 8-bit aligned, src is 8-bit aligned + */ + ldrb r2, [r1] + ldrh r3, [r1, #0x01] + ldrb r1, [r1, #0x03] + strb r2, [r0] + strh r3, [r0, #0x01] + strb r1, [r0, #0x03] + bx lr + LMEMCPY_4_PAD + + +/****************************************************************************** + * Special case for 6 byte copies + */ +#define LMEMCPY_6_LOG2 6 /* 64 bytes */ +#define LMEMCPY_6_PAD .align LMEMCPY_6_LOG2 + LMEMCPY_6_PAD +.Lmemcpy_6: + and r2, r1, #0x03 + orr r2, r2, r0, lsl #2 + ands r2, r2, #0x0f + sub r3, pc, #0x14 + addne pc, r3, r2, lsl #LMEMCPY_6_LOG2 + +/* + * 0000: dst is 32-bit aligned, src is 32-bit aligned + */ + ldr r2, [r1] + ldrh r3, [r1, #0x04] + str r2, [r0] + strh r3, [r0, #0x04] + bx lr + LMEMCPY_6_PAD + +/* + * 0001: dst is 32-bit aligned, src is 8-bit aligned + */ + ldr r2, [r1, #-1] /* BE:r2 = x012 LE:r2 = 210x */ + ldr r3, [r1, #0x03] /* BE:r3 = 345x LE:r3 = x543 */ +#ifdef __ARMEB__ + mov r2, r2, lsl #8 /* r2 = 012. */ + orr r2, r2, r3, lsr #24 /* r2 = 0123 */ +#else + mov r2, r2, lsr #8 /* r2 = .210 */ + orr r2, r2, r3, lsl #24 /* r2 = 3210 */ +#endif + mov r3, r3, lsr #8 /* BE:r3 = .345 LE:r3 = .x54 */ + str r2, [r0] + strh r3, [r0, #0x04] + bx lr + LMEMCPY_6_PAD + +/* + * 0010: dst is 32-bit aligned, src is 16-bit aligned + */ + ldr r3, [r1, #0x02] /* BE:r3 = 2345 LE:r3 = 5432 */ + ldrh r2, [r1] /* BE:r2 = ..01 LE:r2 = ..10 */ +#ifdef __ARMEB__ + mov r1, r3, lsr #16 /* r1 = ..23 */ + orr r1, r1, r2, lsl #16 /* r1 = 0123 */ + str r1, [r0] + strh r3, [r0, #0x04] +#else + mov r1, r3, lsr #16 /* r1 = ..54 */ + orr r2, r2, r3, lsl #16 /* r2 = 3210 */ + str r2, [r0] + strh r1, [r0, #0x04] +#endif + bx lr + LMEMCPY_6_PAD + +/* + * 0011: dst is 32-bit aligned, src is 8-bit aligned + */ + ldr r2, [r1, #-3] /* BE:r2 = xxx0 LE:r2 = 0xxx */ + ldr r3, [r1, #1] /* BE:r3 = 1234 LE:r3 = 4321 */ + ldr r1, [r1, #5] /* BE:r1 = 5xxx LE:r3 = xxx5 */ +#ifdef __ARMEB__ + mov r2, r2, lsl #24 /* r2 = 0... */ + orr r2, r2, r3, lsr #8 /* r2 = 0123 */ + mov r3, r3, lsl #8 /* r3 = 234. */ + orr r1, r3, r1, lsr #24 /* r1 = 2345 */ +#else + mov r2, r2, lsr #24 /* r2 = ...0 */ + orr r2, r2, r3, lsl #8 /* r2 = 3210 */ + mov r1, r1, lsl #8 /* r1 = xx5. */ + orr r1, r1, r3, lsr #24 /* r1 = xx54 */ +#endif + str r2, [r0] + strh r1, [r0, #0x04] + bx lr + LMEMCPY_6_PAD + +/* + * 0100: dst is 8-bit aligned, src is 32-bit aligned + */ + ldr r3, [r1] /* BE:r3 = 0123 LE:r3 = 3210 */ + ldrh r2, [r1, #0x04] /* BE:r2 = ..45 LE:r2 = ..54 */ + mov r1, r3, lsr #8 /* BE:r1 = .012 LE:r1 = .321 */ + strh r1, [r0, #0x01] +#ifdef __ARMEB__ + mov r1, r3, lsr #24 /* r1 = ...0 */ + strb r1, [r0] + mov r3, r3, lsl #8 /* r3 = 123. */ + orr r3, r3, r2, lsr #8 /* r3 = 1234 */ +#else + strb r3, [r0] + mov r3, r3, lsr #24 /* r3 = ...3 */ + orr r3, r3, r2, lsl #8 /* r3 = .543 */ + mov r2, r2, lsr #8 /* r2 = ...5 */ +#endif + strh r3, [r0, #0x03] + strb r2, [r0, #0x05] + bx lr + LMEMCPY_6_PAD + +/* + * 0101: dst is 8-bit aligned, src is 8-bit aligned + */ + ldrb r2, [r1] + ldrh r3, [r1, #0x01] + ldrh ip, [r1, #0x03] + ldrb r1, [r1, #0x05] + strb r2, [r0] + strh r3, [r0, #0x01] + strh ip, [r0, #0x03] + strb r1, [r0, #0x05] + bx lr + LMEMCPY_6_PAD + +/* + * 0110: dst is 8-bit aligned, src is 16-bit aligned + */ + ldrh r2, [r1] /* BE:r2 = ..01 LE:r2 = ..10 */ + ldr r1, [r1, #0x02] /* BE:r1 = 2345 LE:r1 = 5432 */ +#ifdef __ARMEB__ + mov r3, r2, lsr #8 /* r3 = ...0 */ + strb r3, [r0] + strb r1, [r0, #0x05] + mov r3, r1, lsr #8 /* r3 = .234 */ + strh r3, [r0, #0x03] + mov r3, r2, lsl #8 /* r3 = .01. */ + orr r3, r3, r1, lsr #24 /* r3 = .012 */ + strh r3, [r0, #0x01] +#else + strb r2, [r0] + mov r3, r1, lsr #24 + strb r3, [r0, #0x05] + mov r3, r1, lsr #8 /* r3 = .543 */ + strh r3, [r0, #0x03] + mov r3, r2, lsr #8 /* r3 = ...1 */ + orr r3, r3, r1, lsl #8 /* r3 = 4321 */ + strh r3, [r0, #0x01] +#endif + bx lr + LMEMCPY_6_PAD + +/* + * 0111: dst is 8-bit aligned, src is 8-bit aligned + */ + ldrb r2, [r1] + ldrh r3, [r1, #0x01] + ldrh ip, [r1, #0x03] + ldrb r1, [r1, #0x05] + strb r2, [r0] + strh r3, [r0, #0x01] + strh ip, [r0, #0x03] + strb r1, [r0, #0x05] + bx lr + LMEMCPY_6_PAD + +/* + * 1000: dst is 16-bit aligned, src is 32-bit aligned + */ +#ifdef __ARMEB__ + ldr r2, [r1] /* r2 = 0123 */ + ldrh r3, [r1, #0x04] /* r3 = ..45 */ + mov r1, r2, lsr #16 /* r1 = ..01 */ + orr r3, r3, r2, lsl#16 /* r3 = 2345 */ + strh r1, [r0] + str r3, [r0, #0x02] +#else + ldrh r2, [r1, #0x04] /* r2 = ..54 */ + ldr r3, [r1] /* r3 = 3210 */ + mov r2, r2, lsl #16 /* r2 = 54.. */ + orr r2, r2, r3, lsr #16 /* r2 = 5432 */ + strh r3, [r0] + str r2, [r0, #0x02] +#endif + bx lr + LMEMCPY_6_PAD + +/* + * 1001: dst is 16-bit aligned, src is 8-bit aligned + */ + ldr r3, [r1, #-1] /* BE:r3 = x012 LE:r3 = 210x */ + ldr r2, [r1, #3] /* BE:r2 = 345x LE:r2 = x543 */ + mov r1, r3, lsr #8 /* BE:r1 = .x01 LE:r1 = .210 */ +#ifdef __ARMEB__ + mov r2, r2, lsr #8 /* r2 = .345 */ + orr r2, r2, r3, lsl #24 /* r2 = 2345 */ +#else + mov r2, r2, lsl #8 /* r2 = 543. */ + orr r2, r2, r3, lsr #24 /* r2 = 5432 */ +#endif + strh r1, [r0] + str r2, [r0, #0x02] + bx lr + LMEMCPY_6_PAD + +/* + * 1010: dst is 16-bit aligned, src is 16-bit aligned + */ + ldrh r2, [r1] + ldr r3, [r1, #0x02] + strh r2, [r0] + str r3, [r0, #0x02] + bx lr + LMEMCPY_6_PAD + +/* + * 1011: dst is 16-bit aligned, src is 8-bit aligned + */ + ldrb r3, [r1] /* r3 = ...0 */ + ldr r2, [r1, #0x01] /* BE:r2 = 1234 LE:r2 = 4321 */ + ldrb r1, [r1, #0x05] /* r1 = ...5 */ +#ifdef __ARMEB__ + mov r3, r3, lsl #8 /* r3 = ..0. */ + orr r3, r3, r2, lsr #24 /* r3 = ..01 */ + orr r1, r1, r2, lsl #8 /* r1 = 2345 */ +#else + orr r3, r3, r2, lsl #8 /* r3 = 3210 */ + mov r1, r1, lsl #24 /* r1 = 5... */ + orr r1, r1, r2, lsr #8 /* r1 = 5432 */ +#endif + strh r3, [r0] + str r1, [r0, #0x02] + bx lr + LMEMCPY_6_PAD + +/* + * 1100: dst is 8-bit aligned, src is 32-bit aligned + */ + ldr r2, [r1] /* BE:r2 = 0123 LE:r2 = 3210 */ + ldrh r1, [r1, #0x04] /* BE:r1 = ..45 LE:r1 = ..54 */ +#ifdef __ARMEB__ + mov r3, r2, lsr #24 /* r3 = ...0 */ + strb r3, [r0] + mov r2, r2, lsl #8 /* r2 = 123. */ + orr r2, r2, r1, lsr #8 /* r2 = 1234 */ +#else + strb r2, [r0] + mov r2, r2, lsr #8 /* r2 = .321 */ + orr r2, r2, r1, lsl #24 /* r2 = 4321 */ + mov r1, r1, lsr #8 /* r1 = ...5 */ +#endif + str r2, [r0, #0x01] + strb r1, [r0, #0x05] + bx lr + LMEMCPY_6_PAD + +/* + * 1101: dst is 8-bit aligned, src is 8-bit aligned + */ + ldrb r2, [r1] + ldrh r3, [r1, #0x01] + ldrh ip, [r1, #0x03] + ldrb r1, [r1, #0x05] + strb r2, [r0] + strh r3, [r0, #0x01] + strh ip, [r0, #0x03] + strb r1, [r0, #0x05] + bx lr + LMEMCPY_6_PAD + +/* + * 1110: dst is 8-bit aligned, src is 16-bit aligned + */ + ldrh r2, [r1] /* BE:r2 = ..01 LE:r2 = ..10 */ + ldr r1, [r1, #0x02] /* BE:r1 = 2345 LE:r1 = 5432 */ +#ifdef __ARMEB__ + mov r3, r2, lsr #8 /* r3 = ...0 */ + strb r3, [r0] + mov r2, r2, lsl #24 /* r2 = 1... */ + orr r2, r2, r1, lsr #8 /* r2 = 1234 */ +#else + strb r2, [r0] + mov r2, r2, lsr #8 /* r2 = ...1 */ + orr r2, r2, r1, lsl #8 /* r2 = 4321 */ + mov r1, r1, lsr #24 /* r1 = ...5 */ +#endif + str r2, [r0, #0x01] + strb r1, [r0, #0x05] + bx lr + LMEMCPY_6_PAD + +/* + * 1111: dst is 8-bit aligned, src is 8-bit aligned + */ + ldrb r2, [r1] + ldr r3, [r1, #0x01] + ldrb r1, [r1, #0x05] + strb r2, [r0] + str r3, [r0, #0x01] + strb r1, [r0, #0x05] + bx lr + LMEMCPY_6_PAD + + +/****************************************************************************** + * Special case for 8 byte copies + */ +#define LMEMCPY_8_LOG2 6 /* 64 bytes */ +#define LMEMCPY_8_PAD .align LMEMCPY_8_LOG2 + LMEMCPY_8_PAD +.Lmemcpy_8: + and r2, r1, #0x03 + orr r2, r2, r0, lsl #2 + ands r2, r2, #0x0f + sub r3, pc, #0x14 + addne pc, r3, r2, lsl #LMEMCPY_8_LOG2 + +/* + * 0000: dst is 32-bit aligned, src is 32-bit aligned + */ + ldr r2, [r1] + ldr r3, [r1, #0x04] + str r2, [r0] + str r3, [r0, #0x04] + bx lr + LMEMCPY_8_PAD + +/* + * 0001: dst is 32-bit aligned, src is 8-bit aligned + */ + ldr r3, [r1, #-1] /* BE:r3 = x012 LE:r3 = 210x */ + ldr r2, [r1, #0x03] /* BE:r2 = 3456 LE:r2 = 6543 */ + ldrb r1, [r1, #0x07] /* r1 = ...7 */ +#ifdef __ARMEB__ + mov r3, r3, lsl #8 /* r3 = 012. */ + orr r3, r3, r2, lsr #24 /* r3 = 0123 */ + orr r2, r1, r2, lsl #8 /* r2 = 4567 */ +#else + mov r3, r3, lsr #8 /* r3 = .210 */ + orr r3, r3, r2, lsl #24 /* r3 = 3210 */ + mov r1, r1, lsl #24 /* r1 = 7... */ + orr r2, r1, r2, lsr #8 /* r2 = 7654 */ +#endif + str r3, [r0] + str r2, [r0, #0x04] + bx lr + LMEMCPY_8_PAD + +/* + * 0010: dst is 32-bit aligned, src is 16-bit aligned + */ + ldrh r2, [r1] /* BE:r2 = ..01 LE:r2 = ..10 */ + ldr r3, [r1, #0x02] /* BE:r3 = 2345 LE:r3 = 5432 */ + ldrh r1, [r1, #0x06] /* BE:r1 = ..67 LE:r1 = ..76 */ +#ifdef __ARMEB__ + mov r2, r2, lsl #16 /* r2 = 01.. */ + orr r2, r2, r3, lsr #16 /* r2 = 0123 */ + orr r3, r1, r3, lsl #16 /* r3 = 4567 */ +#else + orr r2, r2, r3, lsl #16 /* r2 = 3210 */ + mov r3, r3, lsr #16 /* r3 = ..54 */ + orr r3, r3, r1, lsl #16 /* r3 = 7654 */ +#endif + str r2, [r0] + str r3, [r0, #0x04] + bx lr + LMEMCPY_8_PAD + +/* + * 0011: dst is 32-bit aligned, src is 8-bit aligned + */ + ldrb r3, [r1] /* r3 = ...0 */ + ldr r2, [r1, #0x01] /* BE:r2 = 1234 LE:r2 = 4321 */ + ldr r1, [r1, #0x05] /* BE:r1 = 567x LE:r1 = x765 */ +#ifdef __ARMEB__ + mov r3, r3, lsl #24 /* r3 = 0... */ + orr r3, r3, r2, lsr #8 /* r3 = 0123 */ + mov r2, r2, lsl #24 /* r2 = 4... */ + orr r2, r2, r1, lsr #8 /* r2 = 4567 */ +#else + orr r3, r3, r2, lsl #8 /* r3 = 3210 */ + mov r2, r2, lsr #24 /* r2 = ...4 */ + orr r2, r2, r1, lsl #8 /* r2 = 7654 */ +#endif + str r3, [r0] + str r2, [r0, #0x04] + bx lr + LMEMCPY_8_PAD + +/* + * 0100: dst is 8-bit aligned, src is 32-bit aligned + */ + ldr r3, [r1] /* BE:r3 = 0123 LE:r3 = 3210 */ + ldr r2, [r1, #0x04] /* BE:r2 = 4567 LE:r2 = 7654 */ +#ifdef __ARMEB__ + mov r1, r3, lsr #24 /* r1 = ...0 */ + strb r1, [r0] + mov r1, r3, lsr #8 /* r1 = .012 */ + strb r2, [r0, #0x07] + mov r3, r3, lsl #24 /* r3 = 3... */ + orr r3, r3, r2, lsr #8 /* r3 = 3456 */ +#else + strb r3, [r0] + mov r1, r2, lsr #24 /* r1 = ...7 */ + strb r1, [r0, #0x07] + mov r1, r3, lsr #8 /* r1 = .321 */ + mov r3, r3, lsr #24 /* r3 = ...3 */ + orr r3, r3, r2, lsl #8 /* r3 = 6543 */ +#endif + strh r1, [r0, #0x01] + str r3, [r0, #0x03] + bx lr + LMEMCPY_8_PAD + +/* + * 0101: dst is 8-bit aligned, src is 8-bit aligned + */ + ldrb r2, [r1] + ldrh r3, [r1, #0x01] + ldr ip, [r1, #0x03] + ldrb r1, [r1, #0x07] + strb r2, [r0] + strh r3, [r0, #0x01] + str ip, [r0, #0x03] + strb r1, [r0, #0x07] + bx lr + LMEMCPY_8_PAD + +/* + * 0110: dst is 8-bit aligned, src is 16-bit aligned + */ + ldrh r2, [r1] /* BE:r2 = ..01 LE:r2 = ..10 */ + ldr r3, [r1, #0x02] /* BE:r3 = 2345 LE:r3 = 5432 */ + ldrh r1, [r1, #0x06] /* BE:r1 = ..67 LE:r1 = ..76 */ +#ifdef __ARMEB__ + mov ip, r2, lsr #8 /* ip = ...0 */ + strb ip, [r0] + mov ip, r2, lsl #8 /* ip = .01. */ + orr ip, ip, r3, lsr #24 /* ip = .012 */ + strb r1, [r0, #0x07] + mov r3, r3, lsl #8 /* r3 = 345. */ + orr r3, r3, r1, lsr #8 /* r3 = 3456 */ +#else + strb r2, [r0] /* 0 */ + mov ip, r1, lsr #8 /* ip = ...7 */ + strb ip, [r0, #0x07] /* 7 */ + mov ip, r2, lsr #8 /* ip = ...1 */ + orr ip, ip, r3, lsl #8 /* ip = 4321 */ + mov r3, r3, lsr #8 /* r3 = .543 */ + orr r3, r3, r1, lsl #24 /* r3 = 6543 */ +#endif + strh ip, [r0, #0x01] + str r3, [r0, #0x03] + bx lr + LMEMCPY_8_PAD + +/* + * 0111: dst is 8-bit aligned, src is 8-bit aligned + */ + ldrb r3, [r1] /* r3 = ...0 */ + ldr ip, [r1, #0x01] /* BE:ip = 1234 LE:ip = 4321 */ + ldrh r2, [r1, #0x05] /* BE:r2 = ..56 LE:r2 = ..65 */ + ldrb r1, [r1, #0x07] /* r1 = ...7 */ + strb r3, [r0] + mov r3, ip, lsr #16 /* BE:r3 = ..12 LE:r3 = ..43 */ +#ifdef __ARMEB__ + strh r3, [r0, #0x01] + orr r2, r2, ip, lsl #16 /* r2 = 3456 */ +#else + strh ip, [r0, #0x01] + orr r2, r3, r2, lsl #16 /* r2 = 6543 */ +#endif + str r2, [r0, #0x03] + strb r1, [r0, #0x07] + bx lr + LMEMCPY_8_PAD + +/* + * 1000: dst is 16-bit aligned, src is 32-bit aligned + */ + ldr r2, [r1] /* BE:r2 = 0123 LE:r2 = 3210 */ + ldr r3, [r1, #0x04] /* BE:r3 = 4567 LE:r3 = 7654 */ + mov r1, r2, lsr #16 /* BE:r1 = ..01 LE:r1 = ..32 */ +#ifdef __ARMEB__ + strh r1, [r0] + mov r1, r3, lsr #16 /* r1 = ..45 */ + orr r2, r1 ,r2, lsl #16 /* r2 = 2345 */ +#else + strh r2, [r0] + orr r2, r1, r3, lsl #16 /* r2 = 5432 */ + mov r3, r3, lsr #16 /* r3 = ..76 */ +#endif + str r2, [r0, #0x02] + strh r3, [r0, #0x06] + bx lr + LMEMCPY_8_PAD + +/* + * 1001: dst is 16-bit aligned, src is 8-bit aligned + */ + ldr r2, [r1, #-1] /* BE:r2 = x012 LE:r2 = 210x */ + ldr r3, [r1, #0x03] /* BE:r3 = 3456 LE:r3 = 6543 */ + ldrb ip, [r1, #0x07] /* ip = ...7 */ + mov r1, r2, lsr #8 /* BE:r1 = .x01 LE:r1 = .210 */ + strh r1, [r0] +#ifdef __ARMEB__ + mov r1, r2, lsl #24 /* r1 = 2... */ + orr r1, r1, r3, lsr #8 /* r1 = 2345 */ + orr r3, ip, r3, lsl #8 /* r3 = 4567 */ +#else + mov r1, r2, lsr #24 /* r1 = ...2 */ + orr r1, r1, r3, lsl #8 /* r1 = 5432 */ + mov r3, r3, lsr #24 /* r3 = ...6 */ + orr r3, r3, ip, lsl #8 /* r3 = ..76 */ +#endif + str r1, [r0, #0x02] + strh r3, [r0, #0x06] + bx lr + LMEMCPY_8_PAD + +/* + * 1010: dst is 16-bit aligned, src is 16-bit aligned + */ + ldrh r2, [r1] + ldr ip, [r1, #0x02] + ldrh r3, [r1, #0x06] + strh r2, [r0] + str ip, [r0, #0x02] + strh r3, [r0, #0x06] + bx lr + LMEMCPY_8_PAD + +/* + * 1011: dst is 16-bit aligned, src is 8-bit aligned + */ + ldr r3, [r1, #0x05] /* BE:r3 = 567x LE:r3 = x765 */ + ldr r2, [r1, #0x01] /* BE:r2 = 1234 LE:r2 = 4321 */ + ldrb ip, [r1] /* ip = ...0 */ + mov r1, r3, lsr #8 /* BE:r1 = .567 LE:r1 = .x76 */ + strh r1, [r0, #0x06] +#ifdef __ARMEB__ + mov r3, r3, lsr #24 /* r3 = ...5 */ + orr r3, r3, r2, lsl #8 /* r3 = 2345 */ + mov r2, r2, lsr #24 /* r2 = ...1 */ + orr r2, r2, ip, lsl #8 /* r2 = ..01 */ +#else + mov r3, r3, lsl #24 /* r3 = 5... */ + orr r3, r3, r2, lsr #8 /* r3 = 5432 */ + orr r2, ip, r2, lsl #8 /* r2 = 3210 */ +#endif + str r3, [r0, #0x02] + strh r2, [r0] + bx lr + LMEMCPY_8_PAD + +/* + * 1100: dst is 8-bit aligned, src is 32-bit aligned + */ + ldr r3, [r1, #0x04] /* BE:r3 = 4567 LE:r3 = 7654 */ + ldr r2, [r1] /* BE:r2 = 0123 LE:r2 = 3210 */ + mov r1, r3, lsr #8 /* BE:r1 = .456 LE:r1 = .765 */ + strh r1, [r0, #0x05] +#ifdef __ARMEB__ + strb r3, [r0, #0x07] + mov r1, r2, lsr #24 /* r1 = ...0 */ + strb r1, [r0] + mov r2, r2, lsl #8 /* r2 = 123. */ + orr r2, r2, r3, lsr #24 /* r2 = 1234 */ + str r2, [r0, #0x01] +#else + strb r2, [r0] + mov r1, r3, lsr #24 /* r1 = ...7 */ + strb r1, [r0, #0x07] + mov r2, r2, lsr #8 /* r2 = .321 */ + orr r2, r2, r3, lsl #24 /* r2 = 4321 */ + str r2, [r0, #0x01] +#endif + bx lr + LMEMCPY_8_PAD + +/* + * 1101: dst is 8-bit aligned, src is 8-bit aligned + */ + ldrb r3, [r1] /* r3 = ...0 */ + ldrh r2, [r1, #0x01] /* BE:r2 = ..12 LE:r2 = ..21 */ + ldr ip, [r1, #0x03] /* BE:ip = 3456 LE:ip = 6543 */ + ldrb r1, [r1, #0x07] /* r1 = ...7 */ + strb r3, [r0] + mov r3, ip, lsr #16 /* BE:r3 = ..34 LE:r3 = ..65 */ +#ifdef __ARMEB__ + strh ip, [r0, #0x05] + orr r2, r3, r2, lsl #16 /* r2 = 1234 */ +#else + strh r3, [r0, #0x05] + orr r2, r2, ip, lsl #16 /* r2 = 4321 */ +#endif + str r2, [r0, #0x01] + strb r1, [r0, #0x07] + bx lr + LMEMCPY_8_PAD + +/* + * 1110: dst is 8-bit aligned, src is 16-bit aligned + */ + ldrh r2, [r1] /* BE:r2 = ..01 LE:r2 = ..10 */ + ldr r3, [r1, #0x02] /* BE:r3 = 2345 LE:r3 = 5432 */ + ldrh r1, [r1, #0x06] /* BE:r1 = ..67 LE:r1 = ..76 */ +#ifdef __ARMEB__ + mov ip, r2, lsr #8 /* ip = ...0 */ + strb ip, [r0] + mov ip, r2, lsl #24 /* ip = 1... */ + orr ip, ip, r3, lsr #8 /* ip = 1234 */ + strb r1, [r0, #0x07] + mov r1, r1, lsr #8 /* r1 = ...6 */ + orr r1, r1, r3, lsl #8 /* r1 = 3456 */ +#else + strb r2, [r0] + mov ip, r2, lsr #8 /* ip = ...1 */ + orr ip, ip, r3, lsl #8 /* ip = 4321 */ + mov r2, r1, lsr #8 /* r2 = ...7 */ + strb r2, [r0, #0x07] + mov r1, r1, lsl #8 /* r1 = .76. */ + orr r1, r1, r3, lsr #24 /* r1 = .765 */ +#endif + str ip, [r0, #0x01] + strh r1, [r0, #0x05] + bx lr + LMEMCPY_8_PAD + +/* + * 1111: dst is 8-bit aligned, src is 8-bit aligned + */ + ldrb r2, [r1] + ldr ip, [r1, #0x01] + ldrh r3, [r1, #0x05] + ldrb r1, [r1, #0x07] + strb r2, [r0] + str ip, [r0, #0x01] + strh r3, [r0, #0x05] + strb r1, [r0, #0x07] + bx lr + LMEMCPY_8_PAD + +/****************************************************************************** + * Special case for 12 byte copies + */ +#define LMEMCPY_C_LOG2 7 /* 128 bytes */ +#define LMEMCPY_C_PAD .align LMEMCPY_C_LOG2 + LMEMCPY_C_PAD +.Lmemcpy_c: + and r2, r1, #0x03 + orr r2, r2, r0, lsl #2 + ands r2, r2, #0x0f + sub r3, pc, #0x14 + addne pc, r3, r2, lsl #LMEMCPY_C_LOG2 + +/* + * 0000: dst is 32-bit aligned, src is 32-bit aligned + */ + ldr r2, [r1] + ldr r3, [r1, #0x04] + ldr r1, [r1, #0x08] + str r2, [r0] + str r3, [r0, #0x04] + str r1, [r0, #0x08] + bx lr + LMEMCPY_C_PAD + +/* + * 0001: dst is 32-bit aligned, src is 8-bit aligned + */ + ldrb r2, [r1, #0xb] /* r2 = ...B */ + ldr ip, [r1, #0x07] /* BE:ip = 789A LE:ip = A987 */ + ldr r3, [r1, #0x03] /* BE:r3 = 3456 LE:r3 = 6543 */ + ldr r1, [r1, #-1] /* BE:r1 = x012 LE:r1 = 210x */ +#ifdef __ARMEB__ + orr r2, r2, ip, lsl #8 /* r2 = 89AB */ + str r2, [r0, #0x08] + mov r2, ip, lsr #24 /* r2 = ...7 */ + orr r2, r2, r3, lsl #8 /* r2 = 4567 */ + mov r1, r1, lsl #8 /* r1 = 012. */ + orr r1, r1, r3, lsr #24 /* r1 = 0123 */ +#else + mov r2, r2, lsl #24 /* r2 = B... */ + orr r2, r2, ip, lsr #8 /* r2 = BA98 */ + str r2, [r0, #0x08] + mov r2, ip, lsl #24 /* r2 = 7... */ + orr r2, r2, r3, lsr #8 /* r2 = 7654 */ + mov r1, r1, lsr #8 /* r1 = .210 */ + orr r1, r1, r3, lsl #24 /* r1 = 3210 */ +#endif + str r2, [r0, #0x04] + str r1, [r0] + bx lr + LMEMCPY_C_PAD + +/* + * 0010: dst is 32-bit aligned, src is 16-bit aligned + */ + ldrh r2, [r1] /* BE:r2 = ..01 LE:r2 = ..10 */ + ldr r3, [r1, #0x02] /* BE:r3 = 2345 LE:r3 = 5432 */ + ldr ip, [r1, #0x06] /* BE:ip = 6789 LE:ip = 9876 */ + ldrh r1, [r1, #0x0a] /* BE:r1 = ..AB LE:r1 = ..BA */ +#ifdef __ARMEB__ + mov r2, r2, lsl #16 /* r2 = 01.. */ + orr r2, r2, r3, lsr #16 /* r2 = 0123 */ + str r2, [r0] + mov r3, r3, lsl #16 /* r3 = 45.. */ + orr r3, r3, ip, lsr #16 /* r3 = 4567 */ + orr r1, r1, ip, lsl #16 /* r1 = 89AB */ +#else + orr r2, r2, r3, lsl #16 /* r2 = 3210 */ + str r2, [r0] + mov r3, r3, lsr #16 /* r3 = ..54 */ + orr r3, r3, ip, lsl #16 /* r3 = 7654 */ + mov r1, r1, lsl #16 /* r1 = BA.. */ + orr r1, r1, ip, lsr #16 /* r1 = BA98 */ +#endif + str r3, [r0, #0x04] + str r1, [r0, #0x08] + bx lr + LMEMCPY_C_PAD + +/* + * 0011: dst is 32-bit aligned, src is 8-bit aligned + */ + ldrb r2, [r1] /* r2 = ...0 */ + ldr r3, [r1, #0x01] /* BE:r3 = 1234 LE:r3 = 4321 */ + ldr ip, [r1, #0x05] /* BE:ip = 5678 LE:ip = 8765 */ + ldr r1, [r1, #0x09] /* BE:r1 = 9ABx LE:r1 = xBA9 */ +#ifdef __ARMEB__ + mov r2, r2, lsl #24 /* r2 = 0... */ + orr r2, r2, r3, lsr #8 /* r2 = 0123 */ + str r2, [r0] + mov r3, r3, lsl #24 /* r3 = 4... */ + orr r3, r3, ip, lsr #8 /* r3 = 4567 */ + mov r1, r1, lsr #8 /* r1 = .9AB */ + orr r1, r1, ip, lsl #24 /* r1 = 89AB */ +#else + orr r2, r2, r3, lsl #8 /* r2 = 3210 */ + str r2, [r0] + mov r3, r3, lsr #24 /* r3 = ...4 */ + orr r3, r3, ip, lsl #8 /* r3 = 7654 */ + mov r1, r1, lsl #8 /* r1 = BA9. */ + orr r1, r1, ip, lsr #24 /* r1 = BA98 */ +#endif + str r3, [r0, #0x04] + str r1, [r0, #0x08] + bx lr + LMEMCPY_C_PAD + +/* + * 0100: dst is 8-bit aligned (byte 1), src is 32-bit aligned + */ + ldr r2, [r1] /* BE:r2 = 0123 LE:r2 = 3210 */ + ldr r3, [r1, #0x04] /* BE:r3 = 4567 LE:r3 = 7654 */ + ldr ip, [r1, #0x08] /* BE:ip = 89AB LE:ip = BA98 */ + mov r1, r2, lsr #8 /* BE:r1 = .012 LE:r1 = .321 */ + strh r1, [r0, #0x01] +#ifdef __ARMEB__ + mov r1, r2, lsr #24 /* r1 = ...0 */ + strb r1, [r0] + mov r1, r2, lsl #24 /* r1 = 3... */ + orr r2, r1, r3, lsr #8 /* r1 = 3456 */ + mov r1, r3, lsl #24 /* r1 = 7... */ + orr r1, r1, ip, lsr #8 /* r1 = 789A */ +#else + strb r2, [r0] + mov r1, r2, lsr #24 /* r1 = ...3 */ + orr r2, r1, r3, lsl #8 /* r1 = 6543 */ + mov r1, r3, lsr #24 /* r1 = ...7 */ + orr r1, r1, ip, lsl #8 /* r1 = A987 */ + mov ip, ip, lsr #24 /* ip = ...B */ +#endif + str r2, [r0, #0x03] + str r1, [r0, #0x07] + strb ip, [r0, #0x0b] + bx lr + LMEMCPY_C_PAD + +/* + * 0101: dst is 8-bit aligned (byte 1), src is 8-bit aligned (byte 1) + */ + ldrb r2, [r1] + ldrh r3, [r1, #0x01] + ldr ip, [r1, #0x03] + strb r2, [r0] + ldr r2, [r1, #0x07] + ldrb r1, [r1, #0x0b] + strh r3, [r0, #0x01] + str ip, [r0, #0x03] + str r2, [r0, #0x07] + strb r1, [r0, #0x0b] + bx lr + LMEMCPY_C_PAD + +/* + * 0110: dst is 8-bit aligned (byte 1), src is 16-bit aligned + */ + ldrh r2, [r1] /* BE:r2 = ..01 LE:r2 = ..10 */ + ldr r3, [r1, #0x02] /* BE:r3 = 2345 LE:r3 = 5432 */ + ldr ip, [r1, #0x06] /* BE:ip = 6789 LE:ip = 9876 */ + ldrh r1, [r1, #0x0a] /* BE:r1 = ..AB LE:r1 = ..BA */ +#ifdef __ARMEB__ + mov r2, r2, ror #8 /* r2 = 1..0 */ + strb r2, [r0] + mov r2, r2, lsr #16 /* r2 = ..1. */ + orr r2, r2, r3, lsr #24 /* r2 = ..12 */ + strh r2, [r0, #0x01] + mov r2, r3, lsl #8 /* r2 = 345. */ + orr r3, r2, ip, lsr #24 /* r3 = 3456 */ + mov r2, ip, lsl #8 /* r2 = 789. */ + orr r2, r2, r1, lsr #8 /* r2 = 789A */ +#else + strb r2, [r0] + mov r2, r2, lsr #8 /* r2 = ...1 */ + orr r2, r2, r3, lsl #8 /* r2 = 4321 */ + strh r2, [r0, #0x01] + mov r2, r3, lsr #8 /* r2 = .543 */ + orr r3, r2, ip, lsl #24 /* r3 = 6543 */ + mov r2, ip, lsr #8 /* r2 = .987 */ + orr r2, r2, r1, lsl #24 /* r2 = A987 */ + mov r1, r1, lsr #8 /* r1 = ...B */ +#endif + str r3, [r0, #0x03] + str r2, [r0, #0x07] + strb r1, [r0, #0x0b] + bx lr + LMEMCPY_C_PAD + +/* + * 0111: dst is 8-bit aligned (byte 1), src is 8-bit aligned (byte 3) + */ + ldrb r2, [r1] + ldr r3, [r1, #0x01] /* BE:r3 = 1234 LE:r3 = 4321 */ + ldr ip, [r1, #0x05] /* BE:ip = 5678 LE:ip = 8765 */ + ldr r1, [r1, #0x09] /* BE:r1 = 9ABx LE:r1 = xBA9 */ + strb r2, [r0] +#ifdef __ARMEB__ + mov r2, r3, lsr #16 /* r2 = ..12 */ + strh r2, [r0, #0x01] + mov r3, r3, lsl #16 /* r3 = 34.. */ + orr r3, r3, ip, lsr #16 /* r3 = 3456 */ + mov ip, ip, lsl #16 /* ip = 78.. */ + orr ip, ip, r1, lsr #16 /* ip = 789A */ + mov r1, r1, lsr #8 /* r1 = .9AB */ +#else + strh r3, [r0, #0x01] + mov r3, r3, lsr #16 /* r3 = ..43 */ + orr r3, r3, ip, lsl #16 /* r3 = 6543 */ + mov ip, ip, lsr #16 /* ip = ..87 */ + orr ip, ip, r1, lsl #16 /* ip = A987 */ + mov r1, r1, lsr #16 /* r1 = ..xB */ +#endif + str r3, [r0, #0x03] + str ip, [r0, #0x07] + strb r1, [r0, #0x0b] + bx lr + LMEMCPY_C_PAD + +/* + * 1000: dst is 16-bit aligned, src is 32-bit aligned + */ + ldr ip, [r1] /* BE:ip = 0123 LE:ip = 3210 */ + ldr r3, [r1, #0x04] /* BE:r3 = 4567 LE:r3 = 7654 */ + ldr r2, [r1, #0x08] /* BE:r2 = 89AB LE:r2 = BA98 */ + mov r1, ip, lsr #16 /* BE:r1 = ..01 LE:r1 = ..32 */ +#ifdef __ARMEB__ + strh r1, [r0] + mov r1, ip, lsl #16 /* r1 = 23.. */ + orr r1, r1, r3, lsr #16 /* r1 = 2345 */ + mov r3, r3, lsl #16 /* r3 = 67.. */ + orr r3, r3, r2, lsr #16 /* r3 = 6789 */ +#else + strh ip, [r0] + orr r1, r1, r3, lsl #16 /* r1 = 5432 */ + mov r3, r3, lsr #16 /* r3 = ..76 */ + orr r3, r3, r2, lsl #16 /* r3 = 9876 */ + mov r2, r2, lsr #16 /* r2 = ..BA */ +#endif + str r1, [r0, #0x02] + str r3, [r0, #0x06] + strh r2, [r0, #0x0a] + bx lr + LMEMCPY_C_PAD + +/* + * 1001: dst is 16-bit aligned, src is 8-bit aligned (byte 1) + */ + ldr r2, [r1, #-1] /* BE:r2 = x012 LE:r2 = 210x */ + ldr r3, [r1, #0x03] /* BE:r3 = 3456 LE:r3 = 6543 */ + mov ip, r2, lsr #8 /* BE:ip = .x01 LE:ip = .210 */ + strh ip, [r0] + ldr ip, [r1, #0x07] /* BE:ip = 789A LE:ip = A987 */ + ldrb r1, [r1, #0x0b] /* r1 = ...B */ +#ifdef __ARMEB__ + mov r2, r2, lsl #24 /* r2 = 2... */ + orr r2, r2, r3, lsr #8 /* r2 = 2345 */ + mov r3, r3, lsl #24 /* r3 = 6... */ + orr r3, r3, ip, lsr #8 /* r3 = 6789 */ + orr r1, r1, ip, lsl #8 /* r1 = 89AB */ +#else + mov r2, r2, lsr #24 /* r2 = ...2 */ + orr r2, r2, r3, lsl #8 /* r2 = 5432 */ + mov r3, r3, lsr #24 /* r3 = ...6 */ + orr r3, r3, ip, lsl #8 /* r3 = 9876 */ + mov r1, r1, lsl #8 /* r1 = ..B. */ + orr r1, r1, ip, lsr #24 /* r1 = ..BA */ +#endif + str r2, [r0, #0x02] + str r3, [r0, #0x06] + strh r1, [r0, #0x0a] + bx lr + LMEMCPY_C_PAD + +/* + * 1010: dst is 16-bit aligned, src is 16-bit aligned + */ + ldrh r2, [r1] + ldr r3, [r1, #0x02] + ldr ip, [r1, #0x06] + ldrh r1, [r1, #0x0a] + strh r2, [r0] + str r3, [r0, #0x02] + str ip, [r0, #0x06] + strh r1, [r0, #0x0a] + bx lr + LMEMCPY_C_PAD + +/* + * 1011: dst is 16-bit aligned, src is 8-bit aligned (byte 3) + */ + ldr r2, [r1, #0x09] /* BE:r2 = 9ABx LE:r2 = xBA9 */ + ldr r3, [r1, #0x05] /* BE:r3 = 5678 LE:r3 = 8765 */ + mov ip, r2, lsr #8 /* BE:ip = .9AB LE:ip = .xBA */ + strh ip, [r0, #0x0a] + ldr ip, [r1, #0x01] /* BE:ip = 1234 LE:ip = 4321 */ + ldrb r1, [r1] /* r1 = ...0 */ +#ifdef __ARMEB__ + mov r2, r2, lsr #24 /* r2 = ...9 */ + orr r2, r2, r3, lsl #8 /* r2 = 6789 */ + mov r3, r3, lsr #24 /* r3 = ...5 */ + orr r3, r3, ip, lsl #8 /* r3 = 2345 */ + mov r1, r1, lsl #8 /* r1 = ..0. */ + orr r1, r1, ip, lsr #24 /* r1 = ..01 */ +#else + mov r2, r2, lsl #24 /* r2 = 9... */ + orr r2, r2, r3, lsr #8 /* r2 = 9876 */ + mov r3, r3, lsl #24 /* r3 = 5... */ + orr r3, r3, ip, lsr #8 /* r3 = 5432 */ + orr r1, r1, ip, lsl #8 /* r1 = 3210 */ +#endif + str r2, [r0, #0x06] + str r3, [r0, #0x02] + strh r1, [r0] + bx lr + LMEMCPY_C_PAD + +/* + * 1100: dst is 8-bit aligned (byte 3), src is 32-bit aligned + */ + ldr r2, [r1] /* BE:r2 = 0123 LE:r2 = 3210 */ + ldr ip, [r1, #0x04] /* BE:ip = 4567 LE:ip = 7654 */ + ldr r1, [r1, #0x08] /* BE:r1 = 89AB LE:r1 = BA98 */ +#ifdef __ARMEB__ + mov r3, r2, lsr #24 /* r3 = ...0 */ + strb r3, [r0] + mov r2, r2, lsl #8 /* r2 = 123. */ + orr r2, r2, ip, lsr #24 /* r2 = 1234 */ + str r2, [r0, #0x01] + mov r2, ip, lsl #8 /* r2 = 567. */ + orr r2, r2, r1, lsr #24 /* r2 = 5678 */ + str r2, [r0, #0x05] + mov r2, r1, lsr #8 /* r2 = ..9A */ + strh r2, [r0, #0x09] + strb r1, [r0, #0x0b] +#else + strb r2, [r0] + mov r3, r2, lsr #8 /* r3 = .321 */ + orr r3, r3, ip, lsl #24 /* r3 = 4321 */ + str r3, [r0, #0x01] + mov r3, ip, lsr #8 /* r3 = .765 */ + orr r3, r3, r1, lsl #24 /* r3 = 8765 */ + str r3, [r0, #0x05] + mov r1, r1, lsr #8 /* r1 = .BA9 */ + strh r1, [r0, #0x09] + mov r1, r1, lsr #16 /* r1 = ...B */ + strb r1, [r0, #0x0b] +#endif + bx lr + LMEMCPY_C_PAD + +/* + * 1101: dst is 8-bit aligned (byte 3), src is 8-bit aligned (byte 1) + */ + ldrb r2, [r1, #0x0b] /* r2 = ...B */ + ldr r3, [r1, #0x07] /* BE:r3 = 789A LE:r3 = A987 */ + ldr ip, [r1, #0x03] /* BE:ip = 3456 LE:ip = 6543 */ + ldr r1, [r1, #-1] /* BE:r1 = x012 LE:r1 = 210x */ + strb r2, [r0, #0x0b] +#ifdef __ARMEB__ + strh r3, [r0, #0x09] + mov r3, r3, lsr #16 /* r3 = ..78 */ + orr r3, r3, ip, lsl #16 /* r3 = 5678 */ + mov ip, ip, lsr #16 /* ip = ..34 */ + orr ip, ip, r1, lsl #16 /* ip = 1234 */ + mov r1, r1, lsr #16 /* r1 = ..x0 */ +#else + mov r2, r3, lsr #16 /* r2 = ..A9 */ + strh r2, [r0, #0x09] + mov r3, r3, lsl #16 /* r3 = 87.. */ + orr r3, r3, ip, lsr #16 /* r3 = 8765 */ + mov ip, ip, lsl #16 /* ip = 43.. */ + orr ip, ip, r1, lsr #16 /* ip = 4321 */ + mov r1, r1, lsr #8 /* r1 = .210 */ +#endif + str r3, [r0, #0x05] + str ip, [r0, #0x01] + strb r1, [r0] + bx lr + LMEMCPY_C_PAD + +/* + * 1110: dst is 8-bit aligned (byte 3), src is 16-bit aligned + */ +#ifdef __ARMEB__ + ldrh r2, [r1, #0x0a] /* r2 = ..AB */ + ldr ip, [r1, #0x06] /* ip = 6789 */ + ldr r3, [r1, #0x02] /* r3 = 2345 */ + ldrh r1, [r1] /* r1 = ..01 */ + strb r2, [r0, #0x0b] + mov r2, r2, lsr #8 /* r2 = ...A */ + orr r2, r2, ip, lsl #8 /* r2 = 789A */ + mov ip, ip, lsr #8 /* ip = .678 */ + orr ip, ip, r3, lsl #24 /* ip = 5678 */ + mov r3, r3, lsr #8 /* r3 = .234 */ + orr r3, r3, r1, lsl #24 /* r3 = 1234 */ + mov r1, r1, lsr #8 /* r1 = ...0 */ + strb r1, [r0] + str r3, [r0, #0x01] + str ip, [r0, #0x05] + strh r2, [r0, #0x09] +#else + ldrh r2, [r1] /* r2 = ..10 */ + ldr r3, [r1, #0x02] /* r3 = 5432 */ + ldr ip, [r1, #0x06] /* ip = 9876 */ + ldrh r1, [r1, #0x0a] /* r1 = ..BA */ + strb r2, [r0] + mov r2, r2, lsr #8 /* r2 = ...1 */ + orr r2, r2, r3, lsl #8 /* r2 = 4321 */ + mov r3, r3, lsr #24 /* r3 = ...5 */ + orr r3, r3, ip, lsl #8 /* r3 = 8765 */ + mov ip, ip, lsr #24 /* ip = ...9 */ + orr ip, ip, r1, lsl #8 /* ip = .BA9 */ + mov r1, r1, lsr #8 /* r1 = ...B */ + str r2, [r0, #0x01] + str r3, [r0, #0x05] + strh ip, [r0, #0x09] + strb r1, [r0, #0x0b] +#endif + bx lr + LMEMCPY_C_PAD + +/* + * 1111: dst is 8-bit aligned (byte 3), src is 8-bit aligned (byte 3) + */ + ldrb r2, [r1] + ldr r3, [r1, #0x01] + ldr ip, [r1, #0x05] + strb r2, [r0] + ldrh r2, [r1, #0x09] + ldrb r1, [r1, #0x0b] + str r3, [r0, #0x01] + str ip, [r0, #0x05] + strh r2, [r0, #0x09] + strb r1, [r0, #0x0b] + bx lr +#endif /* !_STANDALONE */ +END(memcpy) + + .section .note.GNU-stack,"",%progbits diff --git a/lib/libpmc/Makefile b/lib/libpmc/Makefile index 196e6b47dd83..48e94a2a078c 100644 --- a/lib/libpmc/Makefile +++ b/lib/libpmc/Makefile @@ -75,6 +75,7 @@ MAN+= pmc.tsc.3 MAN+= pmc.ucf.3 MAN+= pmc.westmere.3 MAN+= pmc.westmereuc.3 +MAN+= pmc.xscale.3 MLINKS+= \ pmc_allocate.3 pmc_release.3 \ diff --git a/lib/libpmc/libpmc.c b/lib/libpmc/libpmc.c index 332a75a0171b..5286533bacdc 100644 --- a/lib/libpmc/libpmc.c +++ b/lib/libpmc/libpmc.c @@ -59,6 +59,10 @@ static int tsc_allocate_pmc(enum pmc_event _pe, char *_ctrspec, struct pmc_op_pmcallocate *_pmc_config); #endif #if defined(__arm__) +#if defined(__XSCALE__) +static int xscale_allocate_pmc(enum pmc_event _pe, char *_ctrspec, + struct pmc_op_pmcallocate *_pmc_config); +#endif static int armv7_allocate_pmc(enum pmc_event _pe, char *_ctrspec, struct pmc_op_pmcallocate *_pmc_config); #endif @@ -136,6 +140,7 @@ struct pmc_class_descr { PMC_CLASSDEP_TABLE(iaf, IAF); PMC_CLASSDEP_TABLE(k8, K8); +PMC_CLASSDEP_TABLE(xscale, XSCALE); PMC_CLASSDEP_TABLE(armv7, ARMV7); PMC_CLASSDEP_TABLE(armv8, ARMV8); PMC_CLASSDEP_TABLE(mips24k, MIPS24K); @@ -181,6 +186,7 @@ static const struct pmc_event_descr cortex_a57_event_table[] = } PMC_MDEP_TABLE(k8, K8, PMC_CLASS_SOFT, PMC_CLASS_TSC); +PMC_MDEP_TABLE(xscale, XSCALE, PMC_CLASS_SOFT, PMC_CLASS_XSCALE); PMC_MDEP_TABLE(cortex_a8, ARMV7, PMC_CLASS_SOFT, PMC_CLASS_ARMV7); PMC_MDEP_TABLE(cortex_a9, ARMV7, PMC_CLASS_SOFT, PMC_CLASS_ARMV7); PMC_MDEP_TABLE(cortex_a53, ARMV8, PMC_CLASS_SOFT, PMC_CLASS_ARMV8); @@ -218,6 +224,9 @@ PMC_CLASS_TABLE_DESC(k8, K8, k8, k8); PMC_CLASS_TABLE_DESC(tsc, TSC, tsc, tsc); #endif #if defined(__arm__) +#if defined(__XSCALE__) +PMC_CLASS_TABLE_DESC(xscale, XSCALE, xscale, xscale); +#endif PMC_CLASS_TABLE_DESC(cortex_a8, ARMV7, cortex_a8, armv7); PMC_CLASS_TABLE_DESC(cortex_a9, ARMV7, cortex_a9, armv7); #endif @@ -748,6 +757,28 @@ soft_allocate_pmc(enum pmc_event pe, char *ctrspec, } #if defined(__arm__) +#if defined(__XSCALE__) + +static struct pmc_event_alias xscale_aliases[] = { + EV_ALIAS("branches", "BRANCH_RETIRED"), + EV_ALIAS("branch-mispredicts", "BRANCH_MISPRED"), + EV_ALIAS("dc-misses", "DC_MISS"), + EV_ALIAS("ic-misses", "IC_MISS"), + EV_ALIAS("instructions", "INSTR_RETIRED"), + EV_ALIAS(NULL, NULL) +}; +static int +xscale_allocate_pmc(enum pmc_event pe, char *ctrspec __unused, + struct pmc_op_pmcallocate *pmc_config __unused) +{ + switch (pe) { + default: + break; + } + + return (0); +} +#endif static struct pmc_event_alias cortex_a8_aliases[] = { EV_ALIAS("dc-misses", "L1_DCACHE_REFILL"), @@ -1206,6 +1237,10 @@ pmc_event_names_of_class(enum pmc_class cl, const char ***eventnames, ev = k8_event_table; count = PMC_EVENT_TABLE_SIZE(k8); break; + case PMC_CLASS_XSCALE: + ev = xscale_event_table; + count = PMC_EVENT_TABLE_SIZE(xscale); + break; case PMC_CLASS_ARMV7: switch (cpu_info.pm_cputype) { default: @@ -1447,6 +1482,12 @@ pmc_init(void) PMC_MDEP_INIT(generic); break; #if defined(__arm__) +#if defined(__XSCALE__) + case PMC_CPU_INTEL_XSCALE: + PMC_MDEP_INIT(xscale); + pmc_class_table[n] = &xscale_class_table_descr; + break; +#endif case PMC_CPU_ARMV7_CORTEX_A8: PMC_MDEP_INIT(cortex_a8); pmc_class_table[n] = &cortex_a8_class_table_descr; @@ -1575,6 +1616,9 @@ _pmc_name_of_event(enum pmc_event pe, enum pmc_cputype cpu) if (pe >= PMC_EV_K8_FIRST && pe <= PMC_EV_K8_LAST) { ev = k8_event_table; evfence = k8_event_table + PMC_EVENT_TABLE_SIZE(k8); + } else if (pe >= PMC_EV_XSCALE_FIRST && pe <= PMC_EV_XSCALE_LAST) { + ev = xscale_event_table; + evfence = xscale_event_table + PMC_EVENT_TABLE_SIZE(xscale); } else if (pe >= PMC_EV_ARMV7_FIRST && pe <= PMC_EV_ARMV7_LAST) { switch (cpu) { case PMC_CPU_ARMV7_CORTEX_A8: diff --git a/lib/libpmc/pmc.3 b/lib/libpmc/pmc.3 index 242a96ad4425..ee9de22d23ce 100644 --- a/lib/libpmc/pmc.3 +++ b/lib/libpmc/pmc.3 @@ -545,6 +545,7 @@ API is .Xr pmc.tsc 3 , .Xr pmc.westmere 3 , .Xr pmc.westmereuc 3 , +.Xr pmc.xscale 3 , .Xr pmc_allocate 3 , .Xr pmc_attach 3 , .Xr pmc_capabilities 3 , diff --git a/lib/libpmc/pmc.xscale.3 b/lib/libpmc/pmc.xscale.3 new file mode 100644 index 000000000000..d5766e347173 --- /dev/null +++ b/lib/libpmc/pmc.xscale.3 @@ -0,0 +1,156 @@ +.\" Copyright (c) 2009, 2010 Rui Paulo. 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. +.\" +.\" $FreeBSD$ +.\" +.Dd December 23, 2009 +.Dt PMC.XSCALE 3 +.Os +.Sh NAME +.Nm pmc.xscale +.Nd measurement events for +.Tn Intel +.Tn XScale +family CPUs +.Sh LIBRARY +.Lb libpmc +.Sh SYNOPSIS +.In pmc.h +.Sh DESCRIPTION +.Tn Intel XScale +CPUs are ARM CPUs based on the ARMv5e core. +.Pp +Second generation cores have 2 counters, while third generation cores +have 4 counters. +Third generation cores also have an increased number of PMC events. +.Pp +.Tn Intel XScale +PMCs are documented in +.Rs +.%B "3rd Generation Intel XScale Microarchitecture Developer's Manual" +.%D May 2007 +.Re +.Ss Event Specifiers (Programmable PMCs) +.Tn Intel XScale +programmable PMCs support the following events: +.Bl -tag -width indent +.It Li IC_FETCH +External memory fetch due to L1 instruction cache miss. +.It Li IC_MISS +Instruction cache or TLB miss. +.It Li DATA_DEPENDENCY_STALLED +A data dependency stalled +.It Li ITLB_MISS +Instruction TLB miss. +.It Li DTLB_MISS +Data TLB miss. +.It Li BRANCH_RETIRED +Branch instruction retired (executed). +.It Li BRANCH_MISPRED +Branch mispredicted. +.It Li INSTR_RETIRED +Instructions retired (executed). +.It Li DC_FULL_CYCLE +L1 data cache buffer full stall. +Event occurs on every cycle the +condition is present. +.It Li DC_FULL_CONTIG +L1 data cache buffer full stall. +Event occurs once for each contiguous sequence of this type of stall. +.It Li DC_ACCESS +L1 data cache access, not including cache operations. +.It Li DC_MISS +L1 data cache miss, not including cache operations. +.It Li DC_WRITEBACK +L1 data cache write-back. +Occurs for each cache line that's written back from the cache. +.It Li PC_CHANGE +Software changed the program counter. +.It Li BRANCH_RETIRED_ALL +Branch instruction retired (executed). +This event counts all branch instructions, indirect or direct. +.It Li INSTR_CYCLE +Count the number of microarchitecture cycles each instruction requires +to issue. +.It Li CP_STALL +Coprocessor stalled the instruction pipeline. +.It Li PC_CHANGE_ALL +Software changed the program counter (includes exceptions). +.It Li PIPELINE_FLUSH +Pipeline flushes due to mispredictions or exceptions. +.It Li BACKEND_STALL +Backend stalled the instruction pipeline. +.It Li MULTIPLIER_USE +Multiplier used. +.It Li MULTIPLIER_STALLED +Multiplier stalled the instruction pipeline. +.It Li DATA_CACHE_STALLED +Data cache stalled the instruction pipeline. +.It Li L2_CACHE_REQ +L2 cache request, not including cache operations. +.It Li L2_CACHE_MISS +L2 cache miss, not including cache operations. +.It Li ADDRESS_BUS_TRANS +Address bus transaction. +.It Li SELF_ADDRESS_BUS_TRANS +Self initiated address bus transaction. +.It Li DATA_BUS_TRANS +Data bus transaction. +.El +.Ss Event Name Aliases +The following table shows the mapping between the PMC-independent +aliases supported by +.Lb libpmc +and the underlying hardware events used. +.Bl -column "branch-mispredicts" "BRANCH_MISPRED" +.It Em Alias Ta Em Event +.It Li branches Ta Li BRANCH_RETIRED +.It Li branch-mispredicts Ta Li BRANCH_MISPRED +.It Li dc-misses Ta Li DC_MISS +.It Li ic-misses Ta Li IC_MISS +.It Li instructions Ta Li INSTR_RETIRED +.El +.Sh SEE ALSO +.Xr pmc 3 , +.Xr pmc.soft 3 , +.Xr pmc_cpuinfo 3 , +.Xr pmclog 3 , +.Xr hwpmc 4 +.Sh HISTORY +The +.Nm pmc +library first appeared in +.Fx 6.0 . +Intel XScale support first appeared in +.Fx 9.0 . +.Sh AUTHORS +.An -nosplit +The +.Lb libpmc +library was written by +.An Joseph Koshy Aq Mt jkoshy@FreeBSD.org . +.Pp +Intel XScale support was added by +.An Rui Paulo Aq Mt rpaulo@FreeBSD.org . +.Sh CAVEATS +The Intel XScale code does not yet support sampling. diff --git a/share/man/man4/man4.arm/Makefile b/share/man/man4/man4.arm/Makefile index b56f4f9ce9dc..f3c241382839 100644 --- a/share/man/man4/man4.arm/Makefile +++ b/share/man/man4/man4.arm/Makefile @@ -16,6 +16,7 @@ MAN= \ imx6_snvs.4 \ imx_wdog.4 \ mge.4 \ + npe.4 \ ti_adc.4 MLINKS= cgem.4 if_cgem.4 diff --git a/share/man/man4/man4.arm/npe.4 b/share/man/man4/man4.arm/npe.4 new file mode 100644 index 000000000000..035dea1a94b4 --- /dev/null +++ b/share/man/man4/man4.arm/npe.4 @@ -0,0 +1,163 @@ +.\" +.\" Copyright (c) 2006 Sam Leffler, Errno Consulting +.\" +.\" 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 DEVELOPERS ``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 DEVELOPERS 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. +.\" +.\" $FreeBSD$ +.\" +.Dd December 4, 2006 +.Dt NPE 4 arm +.Os +.Sh NAME +.Nm npe +.Nd "Intel XScale Network Processing Engine (NPE) Ethernet device driver" +.Sh SYNOPSIS +To compile this driver into the kernel, +place the following lines in your +kernel configuration file: +.Bd -ragged -offset indent +.Cd "device npe" +.Cd "device npe_fw" +.Cd "device firmware" +.Cd "device qmgr" +.Cd "device miibus" +.Ed +.Sh DESCRIPTION +The +.Nm +driver provides support for Ethernet adapters based on the Intel +XScale Network Processing Engine (NPE). +The NPE must be loaded with firmware that is typically distributed +with boards that have this part. +Otherwise the firmware may be obtained at no cost from the Intel web site. +.Pp +The +.Nm +driver supports the following media types: +.Bl -tag -width ".Cm full-duplex" +.It Cm autoselect +Enable autoselection of the media type and options. +.It Cm 10baseT/UTP +Set 10Mbps operation. +.It Cm 100baseTX +Set 100Mbps (Fast Ethernet) operation. +.El +.Pp +The +.Nm +driver supports the following media options: +.Bl -tag -width ".Cm full-duplex" +.It Cm full-duplex +Set full duplex operation. +.El +.Pp +The +.Nm +driver supports polled operation when the system is +configured with device polling support, +.Xr polling 4 . +Note that for multi-port configurations polling and interrupt-style +operation should not be combined as one of the hardware queues +is shared by all ports. +.Pp +For further information on configuring this device, see +.Xr ifconfig 8 . +.\".Pp +.\"The +.\".Nm +.\"driver supports reception and transmission of extended frames +.\"for +.\".Xr vlan 4 . +.\"This capability of +.\".Nm +.\"can be controlled by means of the +.\".Cm vlanmtu +.\"parameter +.\"to +.\".Xr ifconfig 8 . +.Sh HARDWARE +The adapters supported by the +.Nm +driver exist only on boards that have an XScale processor. +.Sh DIAGNOSTICS +.Bl -diag +.It "npe%d: unit %d not supported" +The unit is larger than the maximum number built into the driver. +This should not happen as +.Nm +devices are not really probed for; they are statically enumerated. +.It "npe%d: Cannot find my PHY." +The associated PHY did not appear while probing the MII bus. +The relationship between PHYs and NPEs is statically defined +in the driver and may require alterations to the driver for new boards. +.It "npe%d: unable to allocate memory for %s ... buffers" +There is not enough memory available for allocation. +The driver pre-allocated memory during attach so this should not happen. +.It "npe%d: remember to fix rx q setup" +See +.Sx BUGS +below. +.It "npe%d: free mbuf at entry %u" +An mbuf was unexpectedly found on the device queue; the index of +the queue entry is printed. +.It "npe%d: too many fragments %u" +A frame was dropped on transmit because it was too fragmented and +the logic to de-fragment failed. +This should not happen. +.It "npe%d: device timeout" +The device has stopped responding to the network, or there is a problem with +the network connection (cable). +.El +.Pp +Other diagnostics exist and are not listed here; +they should be self-explanatory. +.Sh SEE ALSO +.Xr altq 4 , +.Xr arp 4 , +.Xr miibus 4 , +.Xr netintro 4 , +.Xr polling 4 , +.Xr qmgr 4 , +.\".Xr vlan 4 , +.Xr ifconfig 8 +.Sh HISTORY +The +.Nm +device driver first appeared in +.Fx 6.3 . +.Sh CAVEATS +This driver has been tested only with dual-port boards using the IXP425 +such as the Gateworks Avila 2348. +Some changes to the driver may be required for other configurations. +.Sh BUGS +The hardware queues are not properly flushed when the interface +is marked down. +.Pp +The assignment of receive traffic classes to hardware queues +is presently incomplete. +Only the first 4 classes are assigned while there are 8 total. +The driver will print +.Dq Li "remember to fix rx q setup" +on startup as a reminder. +For the moment it is not a problem as all traffic arrives classified +with class 0. diff --git a/share/mk/bsd.cpu.mk b/share/mk/bsd.cpu.mk index 44e2435fa14e..1c2c32568da4 100644 --- a/share/mk/bsd.cpu.mk +++ b/share/mk/bsd.cpu.mk @@ -104,7 +104,11 @@ _CPUCFLAGS = -march=${CPUTYPE} . elif ${MACHINE_CPUARCH} == "amd64" _CPUCFLAGS = -march=${CPUTYPE} . elif ${MACHINE_CPUARCH} == "arm" -. if ${CPUTYPE:M*soft*} != "" +. if ${CPUTYPE} == "xscale" +#XXX: gcc doesn't seem to like -mcpu=xscale, and dies while rebuilding itself +#_CPUCFLAGS = -mcpu=xscale +_CPUCFLAGS = -march=armv5te -D__XSCALE__ +. elif ${CPUTYPE:M*soft*} != "" _CPUCFLAGS = -mfloat-abi=softfp . elif ${CPUTYPE} == "cortexa" _CPUCFLAGS = -march=armv7 -mfpu=vfp diff --git a/sys/arm/arm/bcopyinout.S b/sys/arm/arm/bcopyinout.S index f50e4ba9148c..949ea090331b 100644 --- a/sys/arm/arm/bcopyinout.S +++ b/sys/arm/arm/bcopyinout.S @@ -47,6 +47,9 @@ .word _C_LABEL(_min_memcpy_size) __FBSDID("$FreeBSD$"); +#ifdef _ARM_ARCH_5E +#include +#else .text .align 2 @@ -556,6 +559,7 @@ ENTRY(copyout) RET END(copyout) +#endif /* * int badaddr_read_1(const uint8_t *src, uint8_t *dest) diff --git a/sys/arm/arm/bcopyinout_xscale.S b/sys/arm/arm/bcopyinout_xscale.S new file mode 100644 index 000000000000..ca75347d0300 --- /dev/null +++ b/sys/arm/arm/bcopyinout_xscale.S @@ -0,0 +1,958 @@ +/* $NetBSD: bcopyinout_xscale.S,v 1.3 2003/12/15 09:27:18 scw Exp $ */ + +/*- + * Copyright 2003 Wasabi Systems, Inc. + * All rights reserved. + * + * Written by Steve C. Woodford 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. + */ + +#include +__FBSDID("$FreeBSD$"); + + .syntax unified + .text + .align 2 + +#if __ARM_ARCH >= 6 +#define GET_PCB(tmp) \ + mrc p15, 0, tmp, c13, c0, 4; \ + add tmp, tmp, #(TD_PCB) +#else +.Lcurpcb: + .word _C_LABEL(__pcpu) + PC_CURPCB +#define GET_PCB(tmp) \ + ldr tmp, .Lcurpcb +#endif + +/* + * r0 = user space address + * r1 = kernel space address + * r2 = length + * + * Copies bytes from user space to kernel space + */ +ENTRY(copyin) + cmp r2, #0x00 + movle r0, #0x00 + movle pc, lr /* Bail early if length is <= 0 */ + + adds r3, r0, r2 + movcs r0, #EFAULT + RETc(cs) + + ldr r12, =(VM_MAXUSER_ADDRESS + 1) + cmp r3, r12 + movcs r0, #EFAULT + RETc(cs) + + ldr r3, .L_arm_memcpy + ldr r3, [r3] + cmp r3, #0 + beq .Lnormal + ldr r3, .L_min_memcpy_size + ldr r3, [r3] + cmp r2, r3 + blt .Lnormal + stmfd sp!, {r0-r2, r4, lr} + mov r3, r0 + mov r0, r1 + mov r1, r3 + mov r3, #2 /* SRC_IS_USER */ + ldr r4, .L_arm_memcpy + mov lr, pc + ldr pc, [r4] + cmp r0, #0 + ldmfd sp!, {r0-r2, r4, lr} + moveq r0, #0 + RETeq + +.Lnormal: + stmfd sp!, {r10-r11, lr} + + GET_PCB(r10) + ldr r10, [r10] + + mov r3, #0x00 + adr ip, .Lcopyin_fault + ldr r11, [r10, #PCB_ONFAULT] + str ip, [r10, #PCB_ONFAULT] + bl .Lcopyin_guts + str r11, [r10, #PCB_ONFAULT] + mov r0, #0x00 + ldmfd sp!, {r10-r11, pc} + +.Lcopyin_fault: + ldr r0, =EFAULT + str r11, [r10, #PCB_ONFAULT] + cmp r3, #0x00 + ldmfdgt sp!, {r4-r7} /* r3 > 0 Restore r4-r7 */ + ldmfdlt sp!, {r4-r9} /* r3 < 0 Restore r4-r9 */ + ldmfd sp!, {r10-r11, pc} + +.Lcopyin_guts: + pld [r0] + /* Word-align the destination buffer */ + ands ip, r1, #0x03 /* Already word aligned? */ + beq .Lcopyin_wordaligned /* Yup */ + rsb ip, ip, #0x04 + cmp r2, ip /* Enough bytes left to align it? */ + blt .Lcopyin_l4_2 /* Nope. Just copy bytewise */ + sub r2, r2, ip + rsbs ip, ip, #0x03 + addne pc, pc, ip, lsl #3 + nop + ldrbt ip, [r0], #0x01 + strb ip, [r1], #0x01 + ldrbt ip, [r0], #0x01 + strb ip, [r1], #0x01 + ldrbt ip, [r0], #0x01 + strb ip, [r1], #0x01 + cmp r2, #0x00 /* All done? */ + RETeq + + /* Destination buffer is now word aligned */ +.Lcopyin_wordaligned: + ands ip, r0, #0x03 /* Is src also word-aligned? */ + bne .Lcopyin_bad_align /* Nope. Things just got bad */ + cmp r2, #0x08 /* Less than 8 bytes remaining? */ + blt .Lcopyin_w_less_than8 + + /* Quad-align the destination buffer */ + tst r1, #0x07 /* Already quad aligned? */ + ldrtne ip, [r0], #0x04 + strne ip, [r1], #0x04 + subne r2, r2, #0x04 + stmfd sp!, {r4-r9} /* Free up some registers */ + mov r3, #-1 /* Signal restore r4-r9 */ + + /* Destination buffer quad aligned, source is word aligned */ + subs r2, r2, #0x80 + blt .Lcopyin_w_lessthan128 + + /* Copy 128 bytes at a time */ +.Lcopyin_w_loop128: + ldrt r4, [r0], #0x04 /* LD:00-03 */ + ldrt r5, [r0], #0x04 /* LD:04-07 */ + pld [r0, #0x18] /* Prefetch 0x20 */ + ldrt r6, [r0], #0x04 /* LD:08-0b */ + ldrt r7, [r0], #0x04 /* LD:0c-0f */ + ldrt r8, [r0], #0x04 /* LD:10-13 */ + ldrt r9, [r0], #0x04 /* LD:14-17 */ + strd r4, [r1], #0x08 /* ST:00-07 */ + ldrt r4, [r0], #0x04 /* LD:18-1b */ + ldrt r5, [r0], #0x04 /* LD:1c-1f */ + strd r6, [r1], #0x08 /* ST:08-0f */ + ldrt r6, [r0], #0x04 /* LD:20-23 */ + ldrt r7, [r0], #0x04 /* LD:24-27 */ + pld [r0, #0x18] /* Prefetch 0x40 */ + strd r8, [r1], #0x08 /* ST:10-17 */ + ldrt r8, [r0], #0x04 /* LD:28-2b */ + ldrt r9, [r0], #0x04 /* LD:2c-2f */ + strd r4, [r1], #0x08 /* ST:18-1f */ + ldrt r4, [r0], #0x04 /* LD:30-33 */ + ldrt r5, [r0], #0x04 /* LD:34-37 */ + strd r6, [r1], #0x08 /* ST:20-27 */ + ldrt r6, [r0], #0x04 /* LD:38-3b */ + ldrt r7, [r0], #0x04 /* LD:3c-3f */ + strd r8, [r1], #0x08 /* ST:28-2f */ + ldrt r8, [r0], #0x04 /* LD:40-43 */ + ldrt r9, [r0], #0x04 /* LD:44-47 */ + pld [r0, #0x18] /* Prefetch 0x60 */ + strd r4, [r1], #0x08 /* ST:30-37 */ + ldrt r4, [r0], #0x04 /* LD:48-4b */ + ldrt r5, [r0], #0x04 /* LD:4c-4f */ + strd r6, [r1], #0x08 /* ST:38-3f */ + ldrt r6, [r0], #0x04 /* LD:50-53 */ + ldrt r7, [r0], #0x04 /* LD:54-57 */ + strd r8, [r1], #0x08 /* ST:40-47 */ + ldrt r8, [r0], #0x04 /* LD:58-5b */ + ldrt r9, [r0], #0x04 /* LD:5c-5f */ + strd r4, [r1], #0x08 /* ST:48-4f */ + ldrt r4, [r0], #0x04 /* LD:60-63 */ + ldrt r5, [r0], #0x04 /* LD:64-67 */ + pld [r0, #0x18] /* Prefetch 0x80 */ + strd r6, [r1], #0x08 /* ST:50-57 */ + ldrt r6, [r0], #0x04 /* LD:68-6b */ + ldrt r7, [r0], #0x04 /* LD:6c-6f */ + strd r8, [r1], #0x08 /* ST:58-5f */ + ldrt r8, [r0], #0x04 /* LD:70-73 */ + ldrt r9, [r0], #0x04 /* LD:74-77 */ + strd r4, [r1], #0x08 /* ST:60-67 */ + ldrt r4, [r0], #0x04 /* LD:78-7b */ + ldrt r5, [r0], #0x04 /* LD:7c-7f */ + strd r6, [r1], #0x08 /* ST:68-6f */ + strd r8, [r1], #0x08 /* ST:70-77 */ + subs r2, r2, #0x80 + strd r4, [r1], #0x08 /* ST:78-7f */ + bge .Lcopyin_w_loop128 + +.Lcopyin_w_lessthan128: + adds r2, r2, #0x80 /* Adjust for extra sub */ + ldmfdeq sp!, {r4-r9} + RETeq + subs r2, r2, #0x20 + blt .Lcopyin_w_lessthan32 + + /* Copy 32 bytes at a time */ +.Lcopyin_w_loop32: + ldrt r4, [r0], #0x04 + ldrt r5, [r0], #0x04 + pld [r0, #0x18] + ldrt r6, [r0], #0x04 + ldrt r7, [r0], #0x04 + ldrt r8, [r0], #0x04 + ldrt r9, [r0], #0x04 + strd r4, [r1], #0x08 + ldrt r4, [r0], #0x04 + ldrt r5, [r0], #0x04 + strd r6, [r1], #0x08 + strd r8, [r1], #0x08 + subs r2, r2, #0x20 + strd r4, [r1], #0x08 + bge .Lcopyin_w_loop32 + +.Lcopyin_w_lessthan32: + adds r2, r2, #0x20 /* Adjust for extra sub */ + ldmfdeq sp!, {r4-r9} + RETeq /* Return now if done */ + + and r4, r2, #0x18 + rsb r5, r4, #0x18 + subs r2, r2, r4 + add pc, pc, r5, lsl #1 + nop + + /* At least 24 bytes remaining */ + ldrt r4, [r0], #0x04 + ldrt r5, [r0], #0x04 + nop + strd r4, [r1], #0x08 + + /* At least 16 bytes remaining */ + ldrt r4, [r0], #0x04 + ldrt r5, [r0], #0x04 + nop + strd r4, [r1], #0x08 + + /* At least 8 bytes remaining */ + ldrt r4, [r0], #0x04 + ldrt r5, [r0], #0x04 + nop + strd r4, [r1], #0x08 + + /* Less than 8 bytes remaining */ + ldmfd sp!, {r4-r9} + RETeq /* Return now if done */ + mov r3, #0x00 + +.Lcopyin_w_less_than8: + subs r2, r2, #0x04 + ldrtge ip, [r0], #0x04 + strge ip, [r1], #0x04 + RETeq /* Return now if done */ + addlt r2, r2, #0x04 + ldrbt ip, [r0], #0x01 + cmp r2, #0x02 + ldrbtge r2, [r0], #0x01 + strb ip, [r1], #0x01 + ldrbtgt ip, [r0] + strbge r2, [r1], #0x01 + strbgt ip, [r1] + RET + +/* + * At this point, it has not been possible to word align both buffers. + * The destination buffer (r1) is word aligned, but the source buffer + * (r0) is not. + */ +.Lcopyin_bad_align: + stmfd sp!, {r4-r7} + mov r3, #0x01 + bic r0, r0, #0x03 + cmp ip, #2 + ldrt ip, [r0], #0x04 + bgt .Lcopyin_bad3 + beq .Lcopyin_bad2 + b .Lcopyin_bad1 + +.Lcopyin_bad1_loop16: +#ifdef __ARMEB__ + mov r4, ip, lsl #8 +#else + mov r4, ip, lsr #8 +#endif + ldrt r5, [r0], #0x04 + pld [r0, #0x018] + ldrt r6, [r0], #0x04 + ldrt r7, [r0], #0x04 + ldrt ip, [r0], #0x04 +#ifdef __ARMEB__ + orr r4, r4, r5, lsr #24 + mov r5, r5, lsl #8 + orr r5, r5, r6, lsr #24 + mov r6, r6, lsl #8 + orr r6, r6, r7, lsr #24 + mov r7, r7, lsl #8 + orr r7, r7, ip, lsr #24 +#else + orr r4, r4, r5, lsl #24 + mov r5, r5, lsr #8 + orr r5, r5, r6, lsl #24 + mov r6, r6, lsr #8 + orr r6, r6, r7, lsl #24 + mov r7, r7, lsr #8 + orr r7, r7, ip, lsl #24 +#endif + str r4, [r1], #0x04 + str r5, [r1], #0x04 + str r6, [r1], #0x04 + str r7, [r1], #0x04 +.Lcopyin_bad1: + subs r2, r2, #0x10 + bge .Lcopyin_bad1_loop16 + + adds r2, r2, #0x10 + ldmfdeq sp!, {r4-r7} + RETeq /* Return now if done */ + subs r2, r2, #0x04 + sublt r0, r0, #0x03 + blt .Lcopyin_l4 + +.Lcopyin_bad1_loop4: +#ifdef __ARMEB__ + mov r4, ip, lsl #8 +#else + mov r4, ip, lsr #8 +#endif + ldrt ip, [r0], #0x04 + subs r2, r2, #0x04 +#ifdef __ARMEB__ + orr r4, r4, ip, lsr #24 +#else + orr r4, r4, ip, lsl #24 +#endif + str r4, [r1], #0x04 + bge .Lcopyin_bad1_loop4 + sub r0, r0, #0x03 + b .Lcopyin_l4 + +.Lcopyin_bad2_loop16: +#ifdef __ARMEB__ + mov r4, ip, lsl #16 +#else + mov r4, ip, lsr #16 +#endif + ldrt r5, [r0], #0x04 + pld [r0, #0x018] + ldrt r6, [r0], #0x04 + ldrt r7, [r0], #0x04 + ldrt ip, [r0], #0x04 +#ifdef __ARMEB__ + orr r4, r4, r5, lsr #16 + mov r5, r5, lsl #16 + orr r5, r5, r6, lsr #16 + mov r6, r6, lsl #16 + orr r6, r6, r7, lsr #16 + mov r7, r7, lsl #16 + orr r7, r7, ip, lsr #16 +#else + orr r4, r4, r5, lsl #16 + mov r5, r5, lsr #16 + orr r5, r5, r6, lsl #16 + mov r6, r6, lsr #16 + orr r6, r6, r7, lsl #16 + mov r7, r7, lsr #16 + orr r7, r7, ip, lsl #16 +#endif + str r4, [r1], #0x04 + str r5, [r1], #0x04 + str r6, [r1], #0x04 + str r7, [r1], #0x04 +.Lcopyin_bad2: + subs r2, r2, #0x10 + bge .Lcopyin_bad2_loop16 + + adds r2, r2, #0x10 + ldmfdeq sp!, {r4-r7} + RETeq /* Return now if done */ + subs r2, r2, #0x04 + sublt r0, r0, #0x02 + blt .Lcopyin_l4 + +.Lcopyin_bad2_loop4: +#ifdef __ARMEB__ + mov r4, ip, lsl #16 +#else + mov r4, ip, lsr #16 +#endif + ldrt ip, [r0], #0x04 + subs r2, r2, #0x04 +#ifdef __ARMEB__ + orr r4, r4, ip, lsr #16 +#else + orr r4, r4, ip, lsl #16 +#endif + str r4, [r1], #0x04 + bge .Lcopyin_bad2_loop4 + sub r0, r0, #0x02 + b .Lcopyin_l4 + +.Lcopyin_bad3_loop16: +#ifdef __ARMEB__ + mov r4, ip, lsl #24 +#else + mov r4, ip, lsr #24 +#endif + ldrt r5, [r0], #0x04 + pld [r0, #0x018] + ldrt r6, [r0], #0x04 + ldrt r7, [r0], #0x04 + ldrt ip, [r0], #0x04 +#ifdef __ARMEB__ + orr r4, r4, r5, lsr #8 + mov r5, r5, lsl #24 + orr r5, r5, r6, lsr #8 + mov r6, r6, lsl #24 + orr r6, r6, r7, lsr #8 + mov r7, r7, lsl #24 + orr r7, r7, ip, lsr #8 +#else + orr r4, r4, r5, lsl #8 + mov r5, r5, lsr #24 + orr r5, r5, r6, lsl #8 + mov r6, r6, lsr #24 + orr r6, r6, r7, lsl #8 + mov r7, r7, lsr #24 + orr r7, r7, ip, lsl #8 +#endif + str r4, [r1], #0x04 + str r5, [r1], #0x04 + str r6, [r1], #0x04 + str r7, [r1], #0x04 +.Lcopyin_bad3: + subs r2, r2, #0x10 + bge .Lcopyin_bad3_loop16 + + adds r2, r2, #0x10 + ldmfdeq sp!, {r4-r7} + RETeq /* Return now if done */ + subs r2, r2, #0x04 + sublt r0, r0, #0x01 + blt .Lcopyin_l4 + +.Lcopyin_bad3_loop4: +#ifdef __ARMEB__ + mov r4, ip, lsl #24 +#else + mov r4, ip, lsr #24 +#endif + ldrt ip, [r0], #0x04 + subs r2, r2, #0x04 +#ifdef __ARMEB__ + orr r4, r4, ip, lsr #8 +#else + orr r4, r4, ip, lsl #8 +#endif + str r4, [r1], #0x04 + bge .Lcopyin_bad3_loop4 + sub r0, r0, #0x01 + +.Lcopyin_l4: + ldmfd sp!, {r4-r7} + mov r3, #0x00 + adds r2, r2, #0x04 + RETeq +.Lcopyin_l4_2: + rsbs r2, r2, #0x03 + addne pc, pc, r2, lsl #3 + nop + ldrbt ip, [r0], #0x01 + strb ip, [r1], #0x01 + ldrbt ip, [r0], #0x01 + strb ip, [r1], #0x01 + ldrbt ip, [r0] + strb ip, [r1] + RET +END(copyin) + +/* + * r0 = kernel space address + * r1 = user space address + * r2 = length + * + * Copies bytes from kernel space to user space + */ +ENTRY(copyout) + cmp r2, #0x00 + movle r0, #0x00 + movle pc, lr /* Bail early if length is <= 0 */ + + adds r3, r1, r2 + movcs r0, #EFAULT + RETc(cs) + + ldr r12, =(VM_MAXUSER_ADDRESS + 1) + cmp r3, r12 + movcs r0, #EFAULT + RETc(cs) + + ldr r3, .L_arm_memcpy + ldr r3, [r3] + cmp r3, #0 + beq .Lnormale + ldr r3, .L_min_memcpy_size + ldr r3, [r3] + cmp r2, r3 + blt .Lnormale + stmfd sp!, {r0-r2, r4, lr} + mov r3, r0 + mov r0, r1 + mov r1, r3 + mov r3, #1 /* DST_IS_USER */ + ldr r4, .L_arm_memcpy + mov lr, pc + ldr pc, [r4] + cmp r0, #0 + ldmfd sp!, {r0-r2, r4, lr} + moveq r0, #0 + RETeq + +.Lnormale: + stmfd sp!, {r10-r11, lr} + + GET_PCB(r10) + ldr r10, [r10] + + mov r3, #0x00 + adr ip, .Lcopyout_fault + ldr r11, [r10, #PCB_ONFAULT] + str ip, [r10, #PCB_ONFAULT] + bl .Lcopyout_guts + str r11, [r10, #PCB_ONFAULT] + mov r0, #0x00 + ldmfd sp!, {r10-r11, pc} + +.Lcopyout_fault: + ldr r0, =EFAULT + str r11, [r10, #PCB_ONFAULT] + cmp r3, #0x00 + ldmfdgt sp!, {r4-r7} /* r3 > 0 Restore r4-r7 */ + ldmfdlt sp!, {r4-r9} /* r3 < 0 Restore r4-r9 */ + ldmfd sp!, {r10-r11, pc} + +.Lcopyout_guts: + pld [r0] + /* Word-align the destination buffer */ + ands ip, r1, #0x03 /* Already word aligned? */ + beq .Lcopyout_wordaligned /* Yup */ + rsb ip, ip, #0x04 + cmp r2, ip /* Enough bytes left to align it? */ + blt .Lcopyout_l4_2 /* Nope. Just copy bytewise */ + sub r2, r2, ip + rsbs ip, ip, #0x03 + addne pc, pc, ip, lsl #3 + nop + ldrb ip, [r0], #0x01 + strbt ip, [r1], #0x01 + ldrb ip, [r0], #0x01 + strbt ip, [r1], #0x01 + ldrb ip, [r0], #0x01 + strbt ip, [r1], #0x01 + cmp r2, #0x00 /* All done? */ + RETeq + + /* Destination buffer is now word aligned */ +.Lcopyout_wordaligned: + ands ip, r0, #0x03 /* Is src also word-aligned? */ + bne .Lcopyout_bad_align /* Nope. Things just got bad */ + cmp r2, #0x08 /* Less than 8 bytes remaining? */ + blt .Lcopyout_w_less_than8 + + /* Quad-align the destination buffer */ + tst r0, #0x07 /* Already quad aligned? */ + ldrne ip, [r0], #0x04 + subne r2, r2, #0x04 + strtne ip, [r1], #0x04 + + stmfd sp!, {r4-r9} /* Free up some registers */ + mov r3, #-1 /* Signal restore r4-r9 */ + + /* Destination buffer word aligned, source is quad aligned */ + subs r2, r2, #0x80 + blt .Lcopyout_w_lessthan128 + + /* Copy 128 bytes at a time */ +.Lcopyout_w_loop128: + ldrd r4, [r0], #0x08 /* LD:00-07 */ + pld [r0, #0x18] /* Prefetch 0x20 */ + ldrd r6, [r0], #0x08 /* LD:08-0f */ + ldrd r8, [r0], #0x08 /* LD:10-17 */ + strt r4, [r1], #0x04 /* ST:00-03 */ + strt r5, [r1], #0x04 /* ST:04-07 */ + ldrd r4, [r0], #0x08 /* LD:18-1f */ + strt r6, [r1], #0x04 /* ST:08-0b */ + strt r7, [r1], #0x04 /* ST:0c-0f */ + ldrd r6, [r0], #0x08 /* LD:20-27 */ + pld [r0, #0x18] /* Prefetch 0x40 */ + strt r8, [r1], #0x04 /* ST:10-13 */ + strt r9, [r1], #0x04 /* ST:14-17 */ + ldrd r8, [r0], #0x08 /* LD:28-2f */ + strt r4, [r1], #0x04 /* ST:18-1b */ + strt r5, [r1], #0x04 /* ST:1c-1f */ + ldrd r4, [r0], #0x08 /* LD:30-37 */ + strt r6, [r1], #0x04 /* ST:20-23 */ + strt r7, [r1], #0x04 /* ST:24-27 */ + ldrd r6, [r0], #0x08 /* LD:38-3f */ + strt r8, [r1], #0x04 /* ST:28-2b */ + strt r9, [r1], #0x04 /* ST:2c-2f */ + ldrd r8, [r0], #0x08 /* LD:40-47 */ + pld [r0, #0x18] /* Prefetch 0x60 */ + strt r4, [r1], #0x04 /* ST:30-33 */ + strt r5, [r1], #0x04 /* ST:34-37 */ + ldrd r4, [r0], #0x08 /* LD:48-4f */ + strt r6, [r1], #0x04 /* ST:38-3b */ + strt r7, [r1], #0x04 /* ST:3c-3f */ + ldrd r6, [r0], #0x08 /* LD:50-57 */ + strt r8, [r1], #0x04 /* ST:40-43 */ + strt r9, [r1], #0x04 /* ST:44-47 */ + ldrd r8, [r0], #0x08 /* LD:58-4f */ + strt r4, [r1], #0x04 /* ST:48-4b */ + strt r5, [r1], #0x04 /* ST:4c-4f */ + ldrd r4, [r0], #0x08 /* LD:60-67 */ + pld [r0, #0x18] /* Prefetch 0x80 */ + strt r6, [r1], #0x04 /* ST:50-53 */ + strt r7, [r1], #0x04 /* ST:54-57 */ + ldrd r6, [r0], #0x08 /* LD:68-6f */ + strt r8, [r1], #0x04 /* ST:58-5b */ + strt r9, [r1], #0x04 /* ST:5c-5f */ + ldrd r8, [r0], #0x08 /* LD:70-77 */ + strt r4, [r1], #0x04 /* ST:60-63 */ + strt r5, [r1], #0x04 /* ST:64-67 */ + ldrd r4, [r0], #0x08 /* LD:78-7f */ + strt r6, [r1], #0x04 /* ST:68-6b */ + strt r7, [r1], #0x04 /* ST:6c-6f */ + strt r8, [r1], #0x04 /* ST:70-73 */ + strt r9, [r1], #0x04 /* ST:74-77 */ + subs r2, r2, #0x80 + strt r4, [r1], #0x04 /* ST:78-7b */ + strt r5, [r1], #0x04 /* ST:7c-7f */ + bge .Lcopyout_w_loop128 + +.Lcopyout_w_lessthan128: + adds r2, r2, #0x80 /* Adjust for extra sub */ + ldmfdeq sp!, {r4-r9} + RETeq /* Return now if done */ + subs r2, r2, #0x20 + blt .Lcopyout_w_lessthan32 + + /* Copy 32 bytes at a time */ +.Lcopyout_w_loop32: + ldrd r4, [r0], #0x08 + pld [r0, #0x18] + ldrd r6, [r0], #0x08 + ldrd r8, [r0], #0x08 + strt r4, [r1], #0x04 + strt r5, [r1], #0x04 + ldrd r4, [r0], #0x08 + strt r6, [r1], #0x04 + strt r7, [r1], #0x04 + strt r8, [r1], #0x04 + strt r9, [r1], #0x04 + subs r2, r2, #0x20 + strt r4, [r1], #0x04 + strt r5, [r1], #0x04 + bge .Lcopyout_w_loop32 + +.Lcopyout_w_lessthan32: + adds r2, r2, #0x20 /* Adjust for extra sub */ + ldmfdeq sp!, {r4-r9} + RETeq /* Return now if done */ + + and r4, r2, #0x18 + rsb r5, r4, #0x18 + subs r2, r2, r4 + add pc, pc, r5, lsl #1 + nop + + /* At least 24 bytes remaining */ + ldrd r4, [r0], #0x08 + strt r4, [r1], #0x04 + strt r5, [r1], #0x04 + nop + + /* At least 16 bytes remaining */ + ldrd r4, [r0], #0x08 + strt r4, [r1], #0x04 + strt r5, [r1], #0x04 + nop + + /* At least 8 bytes remaining */ + ldrd r4, [r0], #0x08 + strt r4, [r1], #0x04 + strt r5, [r1], #0x04 + nop + + /* Less than 8 bytes remaining */ + ldmfd sp!, {r4-r9} + RETeq /* Return now if done */ + mov r3, #0x00 + +.Lcopyout_w_less_than8: + subs r2, r2, #0x04 + ldrge ip, [r0], #0x04 + strtge ip, [r1], #0x04 + RETeq /* Return now if done */ + addlt r2, r2, #0x04 + ldrb ip, [r0], #0x01 + cmp r2, #0x02 + ldrbge r2, [r0], #0x01 + strbt ip, [r1], #0x01 + ldrbgt ip, [r0] + strbtge r2, [r1], #0x01 + strbtgt ip, [r1] + RET + +/* + * At this point, it has not been possible to word align both buffers. + * The destination buffer (r1) is word aligned, but the source buffer + * (r0) is not. + */ +.Lcopyout_bad_align: + stmfd sp!, {r4-r7} + mov r3, #0x01 + bic r0, r0, #0x03 + cmp ip, #2 + ldr ip, [r0], #0x04 + bgt .Lcopyout_bad3 + beq .Lcopyout_bad2 + b .Lcopyout_bad1 + +.Lcopyout_bad1_loop16: +#ifdef __ARMEB__ + mov r4, ip, lsl #8 +#else + mov r4, ip, lsr #8 +#endif + ldr r5, [r0], #0x04 + pld [r0, #0x018] + ldr r6, [r0], #0x04 + ldr r7, [r0], #0x04 + ldr ip, [r0], #0x04 +#ifdef __ARMEB__ + orr r4, r4, r5, lsr #24 + mov r5, r5, lsl #8 + orr r5, r5, r6, lsr #24 + mov r6, r6, lsl #8 + orr r6, r6, r7, lsr #24 + mov r7, r7, lsl #8 + orr r7, r7, ip, lsr #24 +#else + orr r4, r4, r5, lsl #24 + mov r5, r5, lsr #8 + orr r5, r5, r6, lsl #24 + mov r6, r6, lsr #8 + orr r6, r6, r7, lsl #24 + mov r7, r7, lsr #8 + orr r7, r7, ip, lsl #24 +#endif + strt r4, [r1], #0x04 + strt r5, [r1], #0x04 + strt r6, [r1], #0x04 + strt r7, [r1], #0x04 +.Lcopyout_bad1: + subs r2, r2, #0x10 + bge .Lcopyout_bad1_loop16 + + adds r2, r2, #0x10 + ldmfdeq sp!, {r4-r7} + RETeq /* Return now if done */ + subs r2, r2, #0x04 + sublt r0, r0, #0x03 + blt .Lcopyout_l4 + +.Lcopyout_bad1_loop4: +#ifdef __ARMEB__ + mov r4, ip, lsl #8 +#else + mov r4, ip, lsr #8 +#endif + ldr ip, [r0], #0x04 + subs r2, r2, #0x04 +#ifdef __ARMEB__ + orr r4, r4, ip, lsr #24 +#else + orr r4, r4, ip, lsl #24 +#endif + strt r4, [r1], #0x04 + bge .Lcopyout_bad1_loop4 + sub r0, r0, #0x03 + b .Lcopyout_l4 + +.Lcopyout_bad2_loop16: +#ifdef __ARMEB__ + mov r4, ip, lsl #16 +#else + mov r4, ip, lsr #16 +#endif + ldr r5, [r0], #0x04 + pld [r0, #0x018] + ldr r6, [r0], #0x04 + ldr r7, [r0], #0x04 + ldr ip, [r0], #0x04 +#ifdef __ARMEB__ + orr r4, r4, r5, lsr #16 + mov r5, r5, lsl #16 + orr r5, r5, r6, lsr #16 + mov r6, r6, lsl #16 + orr r6, r6, r7, lsr #16 + mov r7, r7, lsl #16 + orr r7, r7, ip, lsr #16 +#else + orr r4, r4, r5, lsl #16 + mov r5, r5, lsr #16 + orr r5, r5, r6, lsl #16 + mov r6, r6, lsr #16 + orr r6, r6, r7, lsl #16 + mov r7, r7, lsr #16 + orr r7, r7, ip, lsl #16 +#endif + strt r4, [r1], #0x04 + strt r5, [r1], #0x04 + strt r6, [r1], #0x04 + strt r7, [r1], #0x04 +.Lcopyout_bad2: + subs r2, r2, #0x10 + bge .Lcopyout_bad2_loop16 + + adds r2, r2, #0x10 + ldmfdeq sp!, {r4-r7} + RETeq /* Return now if done */ + subs r2, r2, #0x04 + sublt r0, r0, #0x02 + blt .Lcopyout_l4 + +.Lcopyout_bad2_loop4: +#ifdef __ARMEB__ + mov r4, ip, lsl #16 +#else + mov r4, ip, lsr #16 +#endif + ldr ip, [r0], #0x04 + subs r2, r2, #0x04 +#ifdef __ARMEB__ + orr r4, r4, ip, lsr #16 +#else + orr r4, r4, ip, lsl #16 +#endif + strt r4, [r1], #0x04 + bge .Lcopyout_bad2_loop4 + sub r0, r0, #0x02 + b .Lcopyout_l4 + +.Lcopyout_bad3_loop16: +#ifdef __ARMEB__ + mov r4, ip, lsl #24 +#else + mov r4, ip, lsr #24 +#endif + ldr r5, [r0], #0x04 + pld [r0, #0x018] + ldr r6, [r0], #0x04 + ldr r7, [r0], #0x04 + ldr ip, [r0], #0x04 +#ifdef __ARMEB__ + orr r4, r4, r5, lsr #8 + mov r5, r5, lsl #24 + orr r5, r5, r6, lsr #8 + mov r6, r6, lsl #24 + orr r6, r6, r7, lsr #8 + mov r7, r7, lsl #24 + orr r7, r7, ip, lsr #8 +#else + orr r4, r4, r5, lsl #8 + mov r5, r5, lsr #24 + orr r5, r5, r6, lsl #8 + mov r6, r6, lsr #24 + orr r6, r6, r7, lsl #8 + mov r7, r7, lsr #24 + orr r7, r7, ip, lsl #8 +#endif + strt r4, [r1], #0x04 + strt r5, [r1], #0x04 + strt r6, [r1], #0x04 + strt r7, [r1], #0x04 +.Lcopyout_bad3: + subs r2, r2, #0x10 + bge .Lcopyout_bad3_loop16 + + adds r2, r2, #0x10 + ldmfdeq sp!, {r4-r7} + RETeq /* Return now if done */ + subs r2, r2, #0x04 + sublt r0, r0, #0x01 + blt .Lcopyout_l4 + +.Lcopyout_bad3_loop4: +#ifdef __ARMEB__ + mov r4, ip, lsl #24 +#else + mov r4, ip, lsr #24 +#endif + ldr ip, [r0], #0x04 + subs r2, r2, #0x04 +#ifdef __ARMEB__ + orr r4, r4, ip, lsr #8 +#else + orr r4, r4, ip, lsl #8 +#endif + strt r4, [r1], #0x04 + bge .Lcopyout_bad3_loop4 + sub r0, r0, #0x01 + +.Lcopyout_l4: + ldmfd sp!, {r4-r7} + mov r3, #0x00 + adds r2, r2, #0x04 + RETeq +.Lcopyout_l4_2: + rsbs r2, r2, #0x03 + addne pc, pc, r2, lsl #3 + nop + ldrb ip, [r0], #0x01 + strbt ip, [r1], #0x01 + ldrb ip, [r0], #0x01 + strbt ip, [r1], #0x01 + ldrb ip, [r0] + strbt ip, [r1] + RET +END(copyout) + diff --git a/sys/arm/arm/cpufunc.c b/sys/arm/arm/cpufunc.c index c204b013e883..639ae903551a 100644 --- a/sys/arm/arm/cpufunc.c +++ b/sys/arm/arm/cpufunc.c @@ -61,6 +61,10 @@ __FBSDID("$FreeBSD$"); #include +#if defined(CPU_XSCALE_81342) +#include +#endif + /* PRIMARY CACHE VARIABLES */ int arm_picache_size; int arm_picache_line_size; @@ -250,6 +254,109 @@ struct cpu_functions pj4bv7_cpufuncs = { }; #endif /* CPU_MV_PJ4B */ +#if defined(CPU_XSCALE_PXA2X0) + +struct cpu_functions xscale_cpufuncs = { + /* CPU functions */ + + xscale_cpwait, /* cpwait */ + + /* MMU functions */ + + xscale_control, /* control */ + xscale_setttb, /* setttb */ + + /* TLB functions */ + + armv4_tlb_flushID, /* tlb_flushID */ + xscale_tlb_flushID_SE, /* tlb_flushID_SE */ + armv4_tlb_flushD, /* tlb_flushD */ + armv4_tlb_flushD_SE, /* tlb_flushD_SE */ + + /* Cache operations */ + + xscale_cache_syncI_rng, /* icache_sync_range */ + + xscale_cache_purgeD, /* dcache_wbinv_all */ + xscale_cache_purgeD_rng, /* dcache_wbinv_range */ + xscale_cache_flushD_rng, /* dcache_inv_range */ + xscale_cache_cleanD_rng, /* dcache_wb_range */ + + xscale_cache_flushID, /* idcache_inv_all */ + xscale_cache_purgeID, /* idcache_wbinv_all */ + xscale_cache_purgeID_rng, /* idcache_wbinv_range */ + cpufunc_nullop, /* l2cache_wbinv_all */ + (void *)cpufunc_nullop, /* l2cache_wbinv_range */ + (void *)cpufunc_nullop, /* l2cache_inv_range */ + (void *)cpufunc_nullop, /* l2cache_wb_range */ + (void *)cpufunc_nullop, /* l2cache_drain_writebuf */ + + /* Other functions */ + + armv4_drain_writebuf, /* drain_writebuf */ + + xscale_cpu_sleep, /* sleep */ + + /* Soft functions */ + + xscale_context_switch, /* context_switch */ + + xscale_setup /* cpu setup */ +}; +#endif +/* CPU_XSCALE_PXA2X0 */ + +#ifdef CPU_XSCALE_81342 +struct cpu_functions xscalec3_cpufuncs = { + /* CPU functions */ + + xscale_cpwait, /* cpwait */ + + /* MMU functions */ + + xscale_control, /* control */ + xscalec3_setttb, /* setttb */ + + /* TLB functions */ + + armv4_tlb_flushID, /* tlb_flushID */ + xscale_tlb_flushID_SE, /* tlb_flushID_SE */ + armv4_tlb_flushD, /* tlb_flushD */ + armv4_tlb_flushD_SE, /* tlb_flushD_SE */ + + /* Cache operations */ + + xscalec3_cache_syncI_rng, /* icache_sync_range */ + + xscalec3_cache_purgeD, /* dcache_wbinv_all */ + xscalec3_cache_purgeD_rng, /* dcache_wbinv_range */ + xscale_cache_flushD_rng, /* dcache_inv_range */ + xscalec3_cache_cleanD_rng, /* dcache_wb_range */ + + xscale_cache_flushID, /* idcache_inv_all */ + xscalec3_cache_purgeID, /* idcache_wbinv_all */ + xscalec3_cache_purgeID_rng, /* idcache_wbinv_range */ + xscalec3_l2cache_purge, /* l2cache_wbinv_all */ + xscalec3_l2cache_purge_rng, /* l2cache_wbinv_range */ + xscalec3_l2cache_flush_rng, /* l2cache_inv_range */ + xscalec3_l2cache_clean_rng, /* l2cache_wb_range */ + (void *)cpufunc_nullop, /* l2cache_drain_writebuf */ + + /* Other functions */ + + armv4_drain_writebuf, /* drain_writebuf */ + + xscale_cpu_sleep, /* sleep */ + + /* Soft functions */ + + xscalec3_context_switch, /* context_switch */ + + xscale_setup /* cpu setup */ +}; +#endif /* CPU_XSCALE_81342 */ + + #if defined(CPU_FA526) struct cpu_functions fa526_cpufuncs = { /* CPU functions */ @@ -355,7 +462,9 @@ u_int cpu_reset_needs_v4_MMU_disable; /* flag used in locore-v4.s */ #if defined(CPU_ARM9) || \ defined (CPU_ARM9E) || \ defined(CPU_ARM1176) || \ + defined(CPU_XSCALE_PXA2X0) || \ defined(CPU_FA526) || defined(CPU_MV_PJ4B) || \ + defined(CPU_XSCALE_81342) || \ defined(CPU_CORTEXA) || defined(CPU_KRAIT) /* Global cache line sizes, use 32 as default */ @@ -480,7 +589,7 @@ get_cachetype_cp15(void) arm_dcache_align_mask = arm_dcache_align - 1; } } -#endif /* ARM9 */ +#endif /* ARM9 || XSCALE */ /* * Cannot panic here as we may not have a console yet ... @@ -588,6 +697,29 @@ set_cpufuncs(void) } #endif /* CPU_FA526 */ +#if defined(CPU_XSCALE_81342) + if (cputype == CPU_ID_81342) { + cpufuncs = xscalec3_cpufuncs; + cpu_reset_needs_v4_MMU_disable = 1; /* XScale needs it */ + get_cachetype_cp15(); + pmap_pte_init_xscale(); + goto out; + } +#endif /* CPU_XSCALE_81342 */ +#ifdef CPU_XSCALE_PXA2X0 + /* ignore core revision to test PXA2xx CPUs */ + if ((cputype & ~CPU_ID_XSCALE_COREREV_MASK) == CPU_ID_PXA250 || + (cputype & ~CPU_ID_XSCALE_COREREV_MASK) == CPU_ID_PXA27X || + (cputype & ~CPU_ID_XSCALE_COREREV_MASK) == CPU_ID_PXA210) { + + cpufuncs = xscale_cpufuncs; + cpu_reset_needs_v4_MMU_disable = 1; /* XScale needs it */ + get_cachetype_cp15(); + pmap_pte_init_xscale(); + + goto out; + } +#endif /* CPU_XSCALE_PXA2X0 */ /* * Bzzzz. And the answer was ... */ @@ -800,3 +932,71 @@ fa526_setup(void) cpu_control(0xffffffff, cpuctrl); } #endif /* CPU_FA526 */ + +#if defined(CPU_XSCALE_PXA2X0) || defined(CPU_XSCALE_81342) +void +xscale_setup(void) +{ + uint32_t auxctl; + int cpuctrl, cpuctrlmask; + + /* + * The XScale Write Buffer is always enabled. Our option + * is to enable/disable coalescing. Note that bits 6:3 + * must always be enabled. + */ + + cpuctrl = CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_32BP_ENABLE + | CPU_CONTROL_32BD_ENABLE | CPU_CONTROL_SYST_ENABLE + | CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE + | CPU_CONTROL_WBUF_ENABLE | CPU_CONTROL_LABT_ENABLE + | CPU_CONTROL_BPRD_ENABLE; + cpuctrlmask = CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_32BP_ENABLE + | CPU_CONTROL_32BD_ENABLE | CPU_CONTROL_SYST_ENABLE + | CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE + | CPU_CONTROL_WBUF_ENABLE | CPU_CONTROL_ROM_ENABLE + | CPU_CONTROL_BEND_ENABLE | CPU_CONTROL_AFLT_ENABLE + | CPU_CONTROL_LABT_ENABLE | CPU_CONTROL_BPRD_ENABLE + | CPU_CONTROL_CPCLK | CPU_CONTROL_VECRELOC | \ + CPU_CONTROL_L2_ENABLE; + +#ifndef ARM32_DISABLE_ALIGNMENT_FAULTS + cpuctrl |= CPU_CONTROL_AFLT_ENABLE; +#endif + +#ifdef __ARMEB__ + cpuctrl |= CPU_CONTROL_BEND_ENABLE; +#endif + + if (vector_page == ARM_VECTORS_HIGH) + cpuctrl |= CPU_CONTROL_VECRELOC; +#ifdef CPU_XSCALE_CORE3 + cpuctrl |= CPU_CONTROL_L2_ENABLE; +#endif + + /* Clear out the cache */ + cpu_idcache_wbinv_all(); + + /* + * Set the control register. Note that bits 6:3 must always + * be set to 1. + */ +/* cpu_control(cpuctrlmask, cpuctrl);*/ + cpu_control(0xffffffff, cpuctrl); + + /* Make sure write coalescing is turned on */ + __asm __volatile("mrc p15, 0, %0, c1, c0, 1" + : "=r" (auxctl)); +#ifdef XSCALE_NO_COALESCE_WRITES + auxctl |= XSCALE_AUXCTL_K; +#else + auxctl &= ~XSCALE_AUXCTL_K; +#endif +#ifdef CPU_XSCALE_CORE3 + auxctl |= XSCALE_AUXCTL_LLR; + auxctl |= XSCALE_AUXCTL_MD_MASK; +#endif + __asm __volatile("mcr p15, 0, %0, c1, c0, 1" + : : "r" (auxctl)); +} +#endif /* CPU_XSCALE_PXA2X0 */ diff --git a/sys/arm/arm/cpufunc_asm_xscale.S b/sys/arm/arm/cpufunc_asm_xscale.S new file mode 100644 index 000000000000..08e6f169c3cd --- /dev/null +++ b/sys/arm/arm/cpufunc_asm_xscale.S @@ -0,0 +1,509 @@ +/* $NetBSD: cpufunc_asm_xscale.S,v 1.16 2002/08/17 16:36:32 thorpej Exp $ */ + +/*- + * Copyright (c) 2001, 2002 Wasabi Systems, Inc. + * All rights reserved. + * + * Written by Allen Briggs and 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. + * + */ + +/*- + * Copyright (c) 2001 Matt Thomas. + * Copyright (c) 1997,1998 Mark Brinicombe. + * Copyright (c) 1997 Causality 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Causality Limited. + * 4. The name of Causality Limited may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY CAUSALITY LIMITED ``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 CAUSALITY LIMITED 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. + * + * XScale assembly functions for CPU / MMU / TLB specific operations + */ +#include +__FBSDID("$FreeBSD$"); + +#include + +/* + * Size of the XScale core D-cache. + */ +#define DCACHE_SIZE 0x00008000 + +/* + * CPWAIT -- Canonical method to wait for CP15 update. + * From: Intel 80200 manual, section 2.3.3. + * + * NOTE: Clobbers the specified temp reg. + */ +#define CPWAIT_BRANCH \ + sub pc, pc, #4 + +#define CPWAIT(tmp) \ + mrc p15, 0, tmp, c2, c0, 0 /* arbitrary read of CP15 */ ;\ + mov tmp, tmp /* wait for it to complete */ ;\ + CPWAIT_BRANCH /* branch to next insn */ + +#define CPWAIT_AND_RETURN_SHIFTER lsr #32 + +#define CPWAIT_AND_RETURN(tmp) \ + mrc p15, 0, tmp, c2, c0, 0 /* arbitrary read of CP15 */ ;\ + /* Wait for it to complete and branch to the return address */ \ + sub pc, lr, tmp, CPWAIT_AND_RETURN_SHIFTER + +ENTRY(xscale_cpwait) + CPWAIT_AND_RETURN(r0) +END(xscale_cpwait) + +/* + * We need a separate cpu_control() entry point, since we have to + * invalidate the Branch Target Buffer in the event the BPRD bit + * changes in the control register. + */ +ENTRY(xscale_control) + mrc CP15_SCTLR(r3) /* Read the control register */ + bic r2, r3, r0 /* Clear bits */ + eor r2, r2, r1 /* XOR bits */ + + teq r2, r3 /* Only write if there was a change */ + mcrne p15, 0, r0, c7, c5, 6 /* Invalidate the BTB */ + mcrne CP15_SCTLR(r2) /* Write new control register */ + mov r0, r3 /* Return old value */ + + CPWAIT_AND_RETURN(r1) +END(xscale_control) + +/* + * 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(xscale_setttb) +#ifdef CACHE_CLEAN_BLOCK_INTR + mrs r3, cpsr + orr r1, r3, #(PSR_I | PSR_F) + msr cpsr_fsxc, r1 +#endif + stmfd sp!, {r0-r3, lr} + bl _C_LABEL(xscale_cache_cleanID) + mcr p15, 0, r0, c7, c5, 0 /* invalidate I$ and BTB */ + mcr p15, 0, r0, c7, c10, 4 /* drain write and fill buffer */ + + CPWAIT(r0) + + ldmfd sp!, {r0-r3, lr} + + /* Write the TTB */ + mcr p15, 0, r0, c2, c0, 0 + + /* If we have updated the TTB we must flush the TLB */ + mcr p15, 0, r0, c8, c7, 0 /* invalidate I+D TLB */ + + /* The cleanID above means we only need to flush the I cache here */ + mcr p15, 0, r0, c7, c5, 0 /* invalidate I$ and BTB */ + + CPWAIT(r0) + +#ifdef CACHE_CLEAN_BLOCK_INTR + msr cpsr_fsxc, r3 +#endif + RET +END(xscale_setttb) + +/* + * TLB functions + * + */ +ENTRY(xscale_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 */ + CPWAIT_AND_RETURN(r0) +END(xscale_tlb_flushID_SE) + +/* + * Cache functions + */ +ENTRY(xscale_cache_flushID) + mcr p15, 0, r0, c7, c7, 0 /* flush I+D cache */ + CPWAIT_AND_RETURN(r0) +END(xscale_cache_flushID) + +ENTRY(xscale_cache_flushI) + mcr p15, 0, r0, c7, c5, 0 /* flush I cache */ + CPWAIT_AND_RETURN(r0) +END(xscale_cache_flushI) + +ENTRY(xscale_cache_flushD) + mcr p15, 0, r0, c7, c6, 0 /* flush D cache */ + CPWAIT_AND_RETURN(r0) +END(xscale_cache_flushD) + +ENTRY(xscale_cache_flushI_SE) + mcr p15, 0, r0, c7, c5, 1 /* flush I cache single entry */ + CPWAIT_AND_RETURN(r0) +END(xscale_cache_flushI_SE) + +ENTRY(xscale_cache_flushD_SE) + /* + * Errata (rev < 2): Must clean-dcache-line to an address + * before invalidate-dcache-line to an address, or dirty + * bits will not be cleared in the dcache array. + */ + mcr p15, 0, r0, c7, c10, 1 + mcr p15, 0, r0, c7, c6, 1 /* flush D cache single entry */ + CPWAIT_AND_RETURN(r0) +END(xscale_cache_flushD_SE) + +ENTRY(xscale_cache_cleanD_E) + mcr p15, 0, r0, c7, c10, 1 /* clean D cache entry */ + CPWAIT_AND_RETURN(r0) +END(xscale_cache_cleanD_E) + +/* + * Information for the XScale cache clean/purge functions: + * + * * Virtual address of the memory region to use + * * Size of memory region + * + * Note the virtual address for the Data cache clean operation + * does not need to be backed by physical memory, since no loads + * will actually be performed by the allocate-line operation. + * + * Note that the Mini-Data cache MUST be cleaned by executing + * loads from memory mapped into a region reserved exclusively + * for cleaning of the Mini-Data cache. + */ + .data + + .global _C_LABEL(xscale_cache_clean_addr) +_C_LABEL(xscale_cache_clean_addr): + .word 0x00000000 + + .global _C_LABEL(xscale_cache_clean_size) +_C_LABEL(xscale_cache_clean_size): + .word DCACHE_SIZE + + .global _C_LABEL(xscale_minidata_clean_addr) +_C_LABEL(xscale_minidata_clean_addr): + .word 0x00000000 + + .global _C_LABEL(xscale_minidata_clean_size) +_C_LABEL(xscale_minidata_clean_size): + .word 0x00000800 + + .text + +.Lxscale_cache_clean_addr: + .word _C_LABEL(xscale_cache_clean_addr) +.Lxscale_cache_clean_size: + .word _C_LABEL(xscale_cache_clean_size) + +.Lxscale_minidata_clean_addr: + .word _C_LABEL(xscale_minidata_clean_addr) +.Lxscale_minidata_clean_size: + .word _C_LABEL(xscale_minidata_clean_size) + +#ifdef CACHE_CLEAN_BLOCK_INTR +#define XSCALE_CACHE_CLEAN_BLOCK \ + mrs r3, cpsr ; \ + orr r0, r3, #(PSR_I | PSR_F) ; \ + msr cpsr_fsxc, r0 + +#define XSCALE_CACHE_CLEAN_UNBLOCK \ + msr cpsr_fsxc, r3 +#else +#define XSCALE_CACHE_CLEAN_BLOCK + +#define XSCALE_CACHE_CLEAN_UNBLOCK +#endif /* CACHE_CLEAN_BLOCK_INTR */ + +#define XSCALE_CACHE_CLEAN_PROLOGUE \ + XSCALE_CACHE_CLEAN_BLOCK ; \ + ldr r2, .Lxscale_cache_clean_addr ; \ + ldmia r2, {r0, r1} ; \ + /* \ + * BUG ALERT! \ + * \ + * The XScale core has a strange cache eviction bug, which \ + * requires us to use 2x the cache size for the cache clean \ + * and for that area to be aligned to 2 * cache size. \ + * \ + * The work-around is to use 2 areas for cache clean, and to \ + * alternate between them whenever this is done. No one knows \ + * why the work-around works (mmm!). \ + */ \ + eor r0, r0, #(DCACHE_SIZE) ; \ + str r0, [r2] ; \ + add r0, r0, r1 + +#define XSCALE_CACHE_CLEAN_EPILOGUE \ + XSCALE_CACHE_CLEAN_UNBLOCK + +ENTRY_NP(xscale_cache_syncI) + +EENTRY_NP(xscale_cache_purgeID) + mcr p15, 0, r0, c7, c5, 0 /* flush I cache (D cleaned below) */ +EENTRY_NP(xscale_cache_cleanID) +EENTRY_NP(xscale_cache_purgeD) +EENTRY(xscale_cache_cleanD) + XSCALE_CACHE_CLEAN_PROLOGUE + +1: subs r0, r0, #32 + mcr p15, 0, r0, c7, c2, 5 /* allocate cache line */ + subs r1, r1, #32 + bne 1b + + CPWAIT(r0) + + mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */ + + CPWAIT(r0) + + XSCALE_CACHE_CLEAN_EPILOGUE + RET +EEND(xscale_cache_cleanD) +EEND(xscale_cache_purgeD) +EEND(xscale_cache_cleanID) +EEND(xscale_cache_purgeID) +END(xscale_cache_syncI) + +/* + * Clean the mini-data cache. + * + * It's expected that we only use the mini-data cache for + * kernel addresses, so there is no need to purge it on + * context switch, and no need to prevent userspace access + * while we clean it. + */ +ENTRY(xscale_cache_clean_minidata) + ldr r2, .Lxscale_minidata_clean_addr + ldmia r2, {r0, r1} +1: ldr r3, [r0], #32 + subs r1, r1, #32 + bne 1b + + mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */ + + CPWAIT_AND_RETURN(r1) +END(xscale_cache_clean_minidata) + +ENTRY(xscale_cache_purgeID_E) + mcr p15, 0, r0, c7, c10, 1 /* clean D cache entry */ + CPWAIT(r1) + mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */ + mcr p15, 0, r0, c7, c5, 1 /* flush I cache single entry */ + mcr p15, 0, r0, c7, c6, 1 /* flush D cache single entry */ + CPWAIT_AND_RETURN(r1) +END(xscale_cache_purgeID_E) + +ENTRY(xscale_cache_purgeD_E) + mcr p15, 0, r0, c7, c10, 1 /* clean D cache entry */ + CPWAIT(r1) + mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */ + mcr p15, 0, r0, c7, c6, 1 /* flush D cache single entry */ + CPWAIT_AND_RETURN(r1) +END(xscale_cache_purgeD_E) + +/* + * Soft functions + */ +/* xscale_cache_syncI is identical to xscale_cache_purgeID */ + +EENTRY(xscale_cache_cleanID_rng) +ENTRY(xscale_cache_cleanD_rng) + cmp r1, #0x4000 + bcs _C_LABEL(xscale_cache_cleanID) + + and r2, r0, #0x1f + add r1, r1, r2 + bic r0, r0, #0x1f + +1: mcr p15, 0, r0, c7, c10, 1 /* clean D cache entry */ + add r0, r0, #32 + subs r1, r1, #32 + bhi 1b + + CPWAIT(r0) + + mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */ + + CPWAIT_AND_RETURN(r0) +/*END(xscale_cache_cleanID_rng)*/ +END(xscale_cache_cleanD_rng) + +ENTRY(xscale_cache_purgeID_rng) + cmp r1, #0x4000 + bcs _C_LABEL(xscale_cache_purgeID) + + and r2, r0, #0x1f + add r1, r1, r2 + bic r0, r0, #0x1f + +1: mcr p15, 0, r0, c7, c10, 1 /* clean D cache entry */ + mcr p15, 0, r0, c7, c6, 1 /* flush D cache single entry */ + mcr p15, 0, r0, c7, c5, 1 /* flush I cache single entry */ + add r0, r0, #32 + subs r1, r1, #32 + bhi 1b + + CPWAIT(r0) + + mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */ + + CPWAIT_AND_RETURN(r0) +END(xscale_cache_purgeID_rng) + +ENTRY(xscale_cache_purgeD_rng) + cmp r1, #0x4000 + bcs _C_LABEL(xscale_cache_purgeD) + + and r2, r0, #0x1f + add r1, r1, r2 + bic r0, r0, #0x1f + +1: mcr p15, 0, r0, c7, c10, 1 /* clean D cache entry */ + mcr p15, 0, r0, c7, c6, 1 /* flush D cache single entry */ + add r0, r0, #32 + subs r1, r1, #32 + bhi 1b + + CPWAIT(r0) + + mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */ + + CPWAIT_AND_RETURN(r0) +END(xscale_cache_purgeD_rng) + +ENTRY(xscale_cache_syncI_rng) + cmp r1, #0x4000 + bcs _C_LABEL(xscale_cache_syncI) + + and r2, r0, #0x1f + add r1, r1, r2 + bic r0, r0, #0x1f + +1: mcr p15, 0, r0, c7, c10, 1 /* clean D cache entry */ + mcr p15, 0, r0, c7, c5, 1 /* flush I cache single entry */ + add r0, r0, #32 + subs r1, r1, #32 + bhi 1b + + CPWAIT(r0) + + mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */ + + CPWAIT_AND_RETURN(r0) +END(xscale_cache_syncI_rng) + +ENTRY(xscale_cache_flushD_rng) + and r2, r0, #0x1f + add r1, r1, r2 + bic r0, r0, #0x1f + +1: mcr p15, 0, r0, c7, c6, 1 /* flush D cache single entry */ + add r0, r0, #32 + subs r1, r1, #32 + bhi 1b + + mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */ + + CPWAIT_AND_RETURN(r0) +END(xscale_cache_flushD_rng) + +/* + * 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(xscale_context_switch) + /* + * CF_CACHE_PURGE_ID will *ALWAYS* be called prior to this. + * Thus the data cache will contain only kernel data and the + * instruction cache will contain only kernel code, and all + * kernel mappings are shared by all processes. + */ + + /* Write the TTB */ + mcr p15, 0, r0, c2, c0, 0 + + /* If we have updated the TTB we must flush the TLB */ + mcr p15, 0, r0, c8, c7, 0 /* flush the I+D tlb */ + + CPWAIT_AND_RETURN(r0) +END(xscale_context_switch) + +/* + * xscale_cpu_sleep + * + * This is called when there is nothing on any of the run queues. + * We go into IDLE mode so that any IRQ or FIQ will awaken us. + * + * If this is called with anything other than ARM_SLEEP_MODE_IDLE, + * ignore it. + */ +ENTRY(xscale_cpu_sleep) + tst r0, #0x00000000 + bne 1f + mov r0, #0x1 + mcr p14, 0, r0, c7, c0, 0 + +1: + RET +END(xscale_cpu_sleep) + diff --git a/sys/arm/arm/cpufunc_asm_xscale_c3.S b/sys/arm/arm/cpufunc_asm_xscale_c3.S new file mode 100644 index 000000000000..012c4a9dfbbd --- /dev/null +++ b/sys/arm/arm/cpufunc_asm_xscale_c3.S @@ -0,0 +1,399 @@ +/* $NetBSD: cpufunc_asm_xscale.S,v 1.16 2002/08/17 16:36:32 thorpej Exp $ */ + +/*- + * Copyright (c) 2007 Olivier Houchard + * Copyright (c) 2001, 2002 Wasabi Systems, Inc. + * All rights reserved. + * + * Written by Allen Briggs and 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. + * + */ + +/*- + * Copyright (c) 2001 Matt Thomas. + * Copyright (c) 1997,1998 Mark Brinicombe. + * Copyright (c) 1997 Causality 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Causality Limited. + * 4. The name of Causality Limited may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY CAUSALITY LIMITED ``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 CAUSALITY LIMITED 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. + * + * XScale core 3 assembly functions for CPU / MMU / TLB specific operations + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +/* + * Size of the XScale core D-cache. + */ +#define DCACHE_SIZE 0x00008000 + +/* + * CPWAIT -- Canonical method to wait for CP15 update. + * From: Intel 80200 manual, section 2.3.3. + * + * NOTE: Clobbers the specified temp reg. + */ +#define CPWAIT_BRANCH \ + sub pc, pc, #4 + +#define CPWAIT(tmp) \ + mrc p15, 0, tmp, c2, c0, 0 /* arbitrary read of CP15 */ ;\ + mov tmp, tmp /* wait for it to complete */ ;\ + CPWAIT_BRANCH /* branch to next insn */ + +#define CPWAIT_AND_RETURN_SHIFTER lsr #32 + +#define CPWAIT_AND_RETURN(tmp) \ + mrc p15, 0, tmp, c2, c0, 0 /* arbitrary read of CP15 */ ;\ + /* Wait for it to complete and branch to the return address */ \ + sub pc, lr, tmp, CPWAIT_AND_RETURN_SHIFTER + +#define ARM_USE_L2_CACHE + +#define L2_CACHE_SIZE 0x80000 +#define L2_CACHE_WAYS 8 +#define L2_CACHE_LINE_SIZE 32 +#define L2_CACHE_SETS (L2_CACHE_SIZE / \ + (L2_CACHE_WAYS * L2_CACHE_LINE_SIZE)) + +#define L1_DCACHE_SIZE 32 * 1024 +#define L1_DCACHE_WAYS 4 +#define L1_DCACHE_LINE_SIZE 32 +#define L1_DCACHE_SETS (L1_DCACHE_SIZE / \ + (L1_DCACHE_WAYS * L1_DCACHE_LINE_SIZE)) +#ifdef CACHE_CLEAN_BLOCK_INTR +#define XSCALE_CACHE_CLEAN_BLOCK \ + stmfd sp!, {r4} ; \ + mrs r4, cpsr ; \ + orr r0, r4, #(PSR_I | PSR_F) ; \ + msr cpsr_fsxc, r0 + +#define XSCALE_CACHE_CLEAN_UNBLOCK \ + msr cpsr_fsxc, r4 ; \ + ldmfd sp!, {r4} +#else +#define XSCALE_CACHE_CLEAN_BLOCK +#define XSCALE_CACHE_CLEAN_UNBLOCK +#endif /* CACHE_CLEAN_BLOCK_INTR */ + + +ENTRY_NP(xscalec3_cache_syncI) +EENTRY_NP(xscalec3_cache_purgeID) + mcr p15, 0, r0, c7, c5, 0 /* flush I cache (D cleaned below) */ +EENTRY_NP(xscalec3_cache_cleanID) +EENTRY_NP(xscalec3_cache_purgeD) +EENTRY(xscalec3_cache_cleanD) + + XSCALE_CACHE_CLEAN_BLOCK + mov r0, #0 +1: + mov r1, r0, asl #30 + mov r2, #0 +2: + orr r3, r1, r2, asl #5 + mcr p15, 0, r3, c7, c14, 2 /* clean and invalidate */ + add r2, r2, #1 + cmp r2, #L1_DCACHE_SETS + bne 2b + add r0, r0, #1 + cmp r0, #4 + bne 1b + CPWAIT(r0) + XSCALE_CACHE_CLEAN_UNBLOCK + mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */ + + RET +EEND(xscalec3_cache_purgeID) +EEND(xscalec3_cache_cleanID) +EEND(xscalec3_cache_purgeD) +EEND(xscalec3_cache_cleanD) +END(xscalec3_cache_syncI) + +ENTRY(xscalec3_cache_purgeID_rng) + + cmp r1, #0x4000 + bcs _C_LABEL(xscalec3_cache_cleanID) + and r2, r0, #0x1f + add r1, r1, r2 + bic r0, r0, #0x1f + +1: mcr p15, 0, r0, c7, c14, 1 /* clean/invalidate L1 D cache entry */ + nop + mcr p15, 0, r0, c7, c5, 1 /* flush I cache single entry */ + add r0, r0, #32 + subs r1, r1, #32 + bhi 1b + + CPWAIT(r0) + + mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */ + + CPWAIT_AND_RETURN(r0) +END(xscalec3_cache_purgeID_rng) + +ENTRY(xscalec3_cache_syncI_rng) + cmp r1, #0x4000 + bcs _C_LABEL(xscalec3_cache_syncI) + + and r2, r0, #0x1f + add r1, r1, r2 + bic r0, r0, #0x1f + +1: mcr p15, 0, r0, c7, c10, 1 /* clean D cache entry */ + mcr p15, 0, r0, c7, c5, 1 /* flush I cache single entry */ + add r0, r0, #32 + subs r1, r1, #32 + bhi 1b + + CPWAIT(r0) + + mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */ + + CPWAIT_AND_RETURN(r0) +END(xscalec3_cache_syncI_rng) + +ENTRY(xscalec3_cache_purgeD_rng) + + cmp r1, #0x4000 + bcs _C_LABEL(xscalec3_cache_cleanID) + and r2, r0, #0x1f + add r1, r1, r2 + bic r0, r0, #0x1f + +1: mcr p15, 0, r0, c7, c14, 1 /* Clean and invalidate D cache entry */ + add r0, r0, #32 + subs r1, r1, #32 + bhi 1b + + CPWAIT(r0) + + mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */ + + CPWAIT_AND_RETURN(r0) +END(xscalec3_cache_purgeD_rng) + +ENTRY(xscalec3_cache_cleanID_rng) +EENTRY(xscalec3_cache_cleanD_rng) + + cmp r1, #0x4000 + bcs _C_LABEL(xscalec3_cache_cleanID) + and r2, r0, #0x1f + add r1, r1, r2 + bic r0, r0, #0x1f + +1: mcr p15, 0, r0, c7, c10, 1 /* clean L1 D cache entry */ + nop + add r0, r0, #32 + subs r1, r1, #32 + bhi 1b + + CPWAIT(r0) + + mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */ + + CPWAIT_AND_RETURN(r0) +EEND(xscalec3_cache_cleanD_rng) +END(xscalec3_cache_cleanID_rng) + +ENTRY(xscalec3_l2cache_purge) + /* Clean-up the L2 cache */ + mcr p15, 0, r0, c7, c10, 5 /* Data memory barrier */ + mov r0, #0 +1: + mov r1, r0, asl #29 + mov r2, #0 +2: + orr r3, r1, r2, asl #5 + mcr p15, 1, r3, c7, c15, 2 + add r2, r2, #1 + cmp r2, #L2_CACHE_SETS + bne 2b + add r0, r0, #1 + cmp r0, #8 + bne 1b + mcr p15, 0, r0, c7, c10, 4 @ data write barrier + + CPWAIT(r0) + mcr p15, 0, r0, c7, c10, 5 /* Data memory barrier */ + RET +END(xscalec3_l2cache_purge) + +ENTRY(xscalec3_l2cache_clean_rng) + mcr p15, 0, r0, c7, c10, 5 /* Data memory barrier */ + + and r2, r0, #0x1f + add r1, r1, r2 + bic r0, r0, #0x1f + +1: mcr p15, 1, r0, c7, c11, 1 /* Clean L2 D cache entry */ + add r0, r0, #32 + subs r1, r1, #32 + bhi 1b + + + CPWAIT(r0) + + mcr p15, 0, r0, c7, c10, 4 @ data write barrier + mcr p15, 0, r0, c7, c10, 5 + + CPWAIT_AND_RETURN(r0) +END(xscalec3_l2cache_clean_rng) + +ENTRY(xscalec3_l2cache_purge_rng) + + mcr p15, 0, r0, c7, c10, 5 /* Data memory barrier */ + + and r2, r0, #0x1f + add r1, r1, r2 + bic r0, r0, #0x1f + +1: mcr p15, 1, r0, c7, c11, 1 /* Clean L2 D cache entry */ + mcr p15, 1, r0, c7, c7, 1 /* Invalidate L2 D cache entry */ + add r0, r0, #32 + subs r1, r1, #32 + bhi 1b + + mcr p15, 0, r0, c7, c10, 4 @ data write barrier + mcr p15, 0, r0, c7, c10, 5 + + CPWAIT_AND_RETURN(r0) +END(xscalec3_l2cache_purge_rng) + +ENTRY(xscalec3_l2cache_flush_rng) + mcr p15, 0, r0, c7, c10, 5 /* Data memory barrier */ + + and r2, r0, #0x1f + add r1, r1, r2 + bic r0, r0, #0x1f + +1: mcr p15, 1, r0, c7, c7, 1 /* Invalidate L2 cache line */ + add r0, r0, #32 + subs r1, r1, #32 + bhi 1b + mcr p15, 0, r0, c7, c10, 4 @ data write barrier + mcr p15, 0, r0, c7, c10, 5 + CPWAIT_AND_RETURN(r0) +END(xscalec3_l2cache_flush_rng) + +/* + * 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(xscalec3_setttb) +#ifdef CACHE_CLEAN_BLOCK_INTR + mrs r3, cpsr + orr r1, r3, #(PSR_I | PSR_F) + msr cpsr_fsxc, r1 +#endif + stmfd sp!, {r0-r3, lr} + bl _C_LABEL(xscalec3_cache_cleanID) + mcr p15, 0, r0, c7, c5, 0 /* invalidate I$ and BTB */ + mcr p15, 0, r0, c7, c10, 4 /* drain write and fill buffer */ + + CPWAIT(r0) + + ldmfd sp!, {r0-r3, lr} + +#ifdef ARM_USE_L2_CACHE + orr r0, r0, #0x18 /* cache the page table in L2 */ +#endif + /* Write the TTB */ + mcr p15, 0, r0, c2, c0, 0 + + /* If we have updated the TTB we must flush the TLB */ + mcr p15, 0, r0, c8, c7, 0 /* invalidate I+D TLB */ + + CPWAIT(r0) + +#ifdef CACHE_CLEAN_BLOCK_INTR + msr cpsr_fsxc, r3 +#endif + RET +END(xscalec3_setttb) + +/* + * 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(xscalec3_context_switch) + /* + * CF_CACHE_PURGE_ID will *ALWAYS* be called prior to this. + * Thus the data cache will contain only kernel data and the + * instruction cache will contain only kernel code, and all + * kernel mappings are shared by all processes. + */ +#ifdef ARM_USE_L2_CACHE + orr r0, r0, #0x18 /* Cache the page table in L2 */ +#endif + /* Write the TTB */ + mcr p15, 0, r0, c2, c0, 0 + + /* If we have updated the TTB we must flush the TLB */ + mcr p15, 0, r0, c8, c7, 0 /* flush the I+D tlb */ + + CPWAIT_AND_RETURN(r0) +END(xscalec3_context_switch) + diff --git a/sys/arm/arm/dump_machdep.c b/sys/arm/arm/dump_machdep.c index c89a356d6228..ead54ca7b225 100644 --- a/sys/arm/arm/dump_machdep.c +++ b/sys/arm/arm/dump_machdep.c @@ -63,6 +63,9 @@ dumpsys_wbinv_all(void) * part of stopping. */ dcache_wbinv_poc_all(); +#ifdef __XSCALE__ + xscale_cache_clean_minidata(); +#endif } void diff --git a/sys/arm/arm/elf_trampoline.c b/sys/arm/arm/elf_trampoline.c index d090496f5ed2..a43825b072c2 100644 --- a/sys/arm/arm/elf_trampoline.c +++ b/sys/arm/arm/elf_trampoline.c @@ -70,6 +70,16 @@ extern void fa526_idcache_wbinv_all(void); #elif defined(CPU_ARM9E) #define cpu_idcache_wbinv_all armv5_ec_idcache_wbinv_all extern void armv5_ec_idcache_wbinv_all(void); +#elif defined(CPU_XSCALE_PXA2X0) +#define cpu_idcache_wbinv_all xscale_cache_purgeID +extern void xscale_cache_purgeID(void); +#elif defined(CPU_XSCALE_81342) +#define cpu_idcache_wbinv_all xscalec3_cache_purgeID +extern void xscalec3_cache_purgeID(void); +#endif +#ifdef CPU_XSCALE_81342 +#define cpu_l2cache_wbinv_all xscalec3_l2cache_purge +extern void xscalec3_l2cache_purge(void); #elif defined(SOC_MV_KIRKWOOD) || defined(SOC_MV_DISCOVERY) #define cpu_l2cache_wbinv_all sheeva_l2cache_wbinv_all extern void sheeva_l2cache_wbinv_all(void); diff --git a/sys/arm/arm/exception.S b/sys/arm/arm/exception.S index 296441a3a89f..52a7021f2859 100644 --- a/sys/arm/arm/exception.S +++ b/sys/arm/arm/exception.S @@ -321,6 +321,10 @@ END(exception_exit) * on exit (without transitioning back through the abort mode stack). */ ASENTRY_NP(prefetch_abort_entry) +#ifdef __XSCALE__ + nop /* Make absolutely sure any pending */ + nop /* imprecise aborts have occurred. */ +#endif sub lr, lr, #4 /* Adjust the lr. Transition to scv32 */ PUSHFRAMEINSVC /* mode stack, build trapframe there. */ adr lr, exception_exit /* Return from handler via standard */ @@ -337,6 +341,10 @@ END(prefetch_abort_entry) * on exit (without transitioning back through the abort mode stack). */ ASENTRY_NP(data_abort_entry) +#ifdef __XSCALE__ + nop /* Make absolutely sure any pending */ + nop /* imprecise aborts have occurred. */ +#endif sub lr, lr, #8 /* Adjust the lr. Transition to scv32 */ PUSHFRAMEINSVC /* mode stack, build trapframe there. */ adr lr, exception_exit /* Exception exit routine */ diff --git a/sys/arm/arm/identcpu-v4.c b/sys/arm/arm/identcpu-v4.c index 3381eaa032d2..96472f1902fe 100644 --- a/sys/arm/arm/identcpu-v4.c +++ b/sys/arm/arm/identcpu-v4.c @@ -65,6 +65,60 @@ static const char * const generic_steppings[16] = { "rev 12", "rev 13", "rev 14", "rev 15", }; +static const char * const xscale_steppings[16] = { + "step A-0", "step A-1", "step B-0", "step C-0", + "step D-0", "rev 5", "rev 6", "rev 7", + "rev 8", "rev 9", "rev 10", "rev 11", + "rev 12", "rev 13", "rev 14", "rev 15", +}; + +static const char * const i80219_steppings[16] = { + "step A-0", "rev 1", "rev 2", "rev 3", + "rev 4", "rev 5", "rev 6", "rev 7", + "rev 8", "rev 9", "rev 10", "rev 11", + "rev 12", "rev 13", "rev 14", "rev 15", +}; + +static const char * const i80321_steppings[16] = { + "step A-0", "step B-0", "rev 2", "rev 3", + "rev 4", "rev 5", "rev 6", "rev 7", + "rev 8", "rev 9", "rev 10", "rev 11", + "rev 12", "rev 13", "rev 14", "rev 15", +}; + +static const char * const i81342_steppings[16] = { + "step A-0", "rev 1", "rev 2", "rev 3", + "rev 4", "rev 5", "rev 6", "rev 7", + "rev 8", "rev 9", "rev 10", "rev 11", + "rev 12", "rev 13", "rev 14", "rev 15", +}; + +/* Steppings for PXA2[15]0 */ +static const char * const pxa2x0_steppings[16] = { + "step A-0", "step A-1", "step B-0", "step B-1", + "step B-2", "step C-0", "rev 6", "rev 7", + "rev 8", "rev 9", "rev 10", "rev 11", + "rev 12", "rev 13", "rev 14", "rev 15", +}; + +/* Steppings for PXA255/26x. + * rev 5: PXA26x B0, rev 6: PXA255 A0 + */ +static const char * const pxa255_steppings[16] = { + "rev 0", "rev 1", "rev 2", "step A-0", + "rev 4", "step B-0", "step A-0", "rev 7", + "rev 8", "rev 9", "rev 10", "rev 11", + "rev 12", "rev 13", "rev 14", "rev 15", +}; + +/* Stepping for PXA27x */ +static const char * const pxa27x_steppings[16] = { + "step A-0", "step A-1", "step B-0", "step B-1", + "step C-0", "rev 5", "rev 6", "rev 7", + "rev 8", "rev 9", "rev 10", "rev 11", + "rev 12", "rev 13", "rev 14", "rev 15", +}; + struct cpuidtab { u_int32_t cpuid; enum cpu_class cpu_class; @@ -104,6 +158,41 @@ const struct cpuidtab cpuids[] = { { CPU_ID_ARM1026EJS, CPU_CLASS_ARM10EJ, "ARM1026EJ-S", generic_steppings }, + { CPU_ID_80200, CPU_CLASS_XSCALE, "i80200", + xscale_steppings }, + + { CPU_ID_80321_400, CPU_CLASS_XSCALE, "i80321 400MHz", + i80321_steppings }, + { CPU_ID_80321_600, CPU_CLASS_XSCALE, "i80321 600MHz", + i80321_steppings }, + { CPU_ID_80321_400_B0, CPU_CLASS_XSCALE, "i80321 400MHz", + i80321_steppings }, + { CPU_ID_80321_600_B0, CPU_CLASS_XSCALE, "i80321 600MHz", + i80321_steppings }, + + { CPU_ID_81342, CPU_CLASS_XSCALE, "i81342", + i81342_steppings }, + + { CPU_ID_80219_400, CPU_CLASS_XSCALE, "i80219 400MHz", + i80219_steppings }, + { CPU_ID_80219_600, CPU_CLASS_XSCALE, "i80219 600MHz", + i80219_steppings }, + + { CPU_ID_PXA27X, CPU_CLASS_XSCALE, "PXA27x", + pxa27x_steppings }, + { CPU_ID_PXA250A, CPU_CLASS_XSCALE, "PXA250", + pxa2x0_steppings }, + { CPU_ID_PXA210A, CPU_CLASS_XSCALE, "PXA210", + pxa2x0_steppings }, + { CPU_ID_PXA250B, CPU_CLASS_XSCALE, "PXA250", + pxa2x0_steppings }, + { CPU_ID_PXA210B, CPU_CLASS_XSCALE, "PXA210", + pxa2x0_steppings }, + { CPU_ID_PXA250C, CPU_CLASS_XSCALE, "PXA255", + pxa255_steppings }, + { CPU_ID_PXA210C, CPU_CLASS_XSCALE, "PXA210", + pxa2x0_steppings }, + { CPU_ID_MV88FR131, CPU_CLASS_MARVELL, "Feroceon 88FR131", generic_steppings }, @@ -125,6 +214,7 @@ const struct cpu_classtab cpu_classes[] = { { "ARM9EJ-S", "CPU_ARM9E" }, /* CPU_CLASS_ARM9EJS */ { "ARM10E", "CPU_ARM10" }, /* CPU_CLASS_ARM10E */ { "ARM10EJ", "CPU_ARM10" }, /* CPU_CLASS_ARM10EJ */ + { "XScale", "CPU_XSCALE_..." }, /* CPU_CLASS_XSCALE */ { "Marvell", "CPU_MARVELL" }, /* CPU_CLASS_MARVELL */ }; @@ -223,9 +313,13 @@ identify_arm_cpu(void) case CPU_CLASS_ARM9EJS: case CPU_CLASS_ARM10E: case CPU_CLASS_ARM10EJ: + case CPU_CLASS_XSCALE: case CPU_CLASS_MARVELL: print_enadis(ctrl & CPU_CONTROL_DC_ENABLE, "DC"); print_enadis(ctrl & CPU_CONTROL_IC_ENABLE, "IC"); +#ifdef CPU_XSCALE_81342 + print_enadis(ctrl & CPU_CONTROL_L2_ENABLE, "L2"); +#endif #if defined(SOC_MV_KIRKWOOD) || defined(SOC_MV_DISCOVERY) i = sheeva_control_ext(0, 0); print_enadis(i & MV_WA_ENABLE, "WA"); diff --git a/sys/arm/arm/pmap-v4.c b/sys/arm/arm/pmap-v4.c index 2734c9f7fbb1..e7eddadfad91 100644 --- a/sys/arm/arm/pmap-v4.c +++ b/sys/arm/arm/pmap-v4.c @@ -406,6 +406,10 @@ static struct rwlock pvh_global_lock; void pmap_copy_page_offs_generic(vm_paddr_t a_phys, vm_offset_t a_offs, vm_paddr_t b_phys, vm_offset_t b_offs, int cnt); +#if ARM_MMU_XSCALE == 1 +void pmap_copy_page_offs_xscale(vm_paddr_t a_phys, vm_offset_t a_offs, + vm_paddr_t b_phys, vm_offset_t b_offs, int cnt); +#endif /* * This list exists for the benefit of pmap_map_chunk(). It keeps track @@ -497,6 +501,176 @@ pmap_pte_init_generic(void) #endif /* ARM_MMU_GENERIC != 0 */ +#if ARM_MMU_XSCALE == 1 +#if (ARM_NMMUS > 1) || defined (CPU_XSCALE_CORE3) +static u_int xscale_use_minidata; +#endif + +void +pmap_pte_init_xscale(void) +{ + uint32_t auxctl; + int write_through = 0; + + pte_l1_s_cache_mode = L1_S_B|L1_S_C|L1_S_XSCALE_P; + pte_l1_s_cache_mask = L1_S_CACHE_MASK_xscale; + + pte_l2_l_cache_mode = L2_B|L2_C; + pte_l2_l_cache_mask = L2_L_CACHE_MASK_xscale; + + pte_l2_s_cache_mode = L2_B|L2_C; + pte_l2_s_cache_mask = L2_S_CACHE_MASK_xscale; + + pte_l1_s_cache_mode_pt = L1_S_C; + pte_l2_l_cache_mode_pt = L2_C; + pte_l2_s_cache_mode_pt = L2_C; +#ifdef XSCALE_CACHE_READ_WRITE_ALLOCATE + /* + * The XScale core has an enhanced mode where writes that + * miss the cache cause a cache line to be allocated. This + * is significantly faster than the traditional, write-through + * behavior of this case. + */ + pte_l1_s_cache_mode |= L1_S_XSCALE_TEX(TEX_XSCALE_X); + pte_l2_l_cache_mode |= L2_XSCALE_L_TEX(TEX_XSCALE_X); + pte_l2_s_cache_mode |= L2_XSCALE_T_TEX(TEX_XSCALE_X); +#endif /* XSCALE_CACHE_READ_WRITE_ALLOCATE */ +#ifdef XSCALE_CACHE_WRITE_THROUGH + /* + * Some versions of the XScale core have various bugs in + * their cache units, the work-around for which is to run + * the cache in write-through mode. Unfortunately, this + * has a major (negative) impact on performance. So, we + * go ahead and run fast-and-loose, in the hopes that we + * don't line up the planets in a way that will trip the + * bugs. + * + * However, we give you the option to be slow-but-correct. + */ + write_through = 1; +#elif defined(XSCALE_CACHE_WRITE_BACK) + /* force write back cache mode */ + write_through = 0; +#elif defined(CPU_XSCALE_PXA2X0) + /* + * Intel PXA2[15]0 processors are known to have a bug in + * write-back cache on revision 4 and earlier (stepping + * A[01] and B[012]). Fixed for C0 and later. + */ + { + uint32_t id, type; + + id = cpu_ident(); + type = id & ~(CPU_ID_XSCALE_COREREV_MASK|CPU_ID_REVISION_MASK); + + if (type == CPU_ID_PXA250 || type == CPU_ID_PXA210) { + if ((id & CPU_ID_REVISION_MASK) < 5) { + /* write through for stepping A0-1 and B0-2 */ + write_through = 1; + } + } + } +#endif /* XSCALE_CACHE_WRITE_THROUGH */ + + if (write_through) { + pte_l1_s_cache_mode = L1_S_C; + pte_l2_l_cache_mode = L2_C; + pte_l2_s_cache_mode = L2_C; + } + +#if (ARM_NMMUS > 1) + xscale_use_minidata = 1; +#endif + + pte_l2_s_prot_u = L2_S_PROT_U_xscale; + pte_l2_s_prot_w = L2_S_PROT_W_xscale; + pte_l2_s_prot_mask = L2_S_PROT_MASK_xscale; + + pte_l1_s_proto = L1_S_PROTO_xscale; + pte_l1_c_proto = L1_C_PROTO_xscale; + pte_l2_s_proto = L2_S_PROTO_xscale; + +#ifdef CPU_XSCALE_CORE3 + pmap_copy_page_func = pmap_copy_page_generic; + pmap_copy_page_offs_func = pmap_copy_page_offs_generic; + pmap_zero_page_func = pmap_zero_page_generic; + xscale_use_minidata = 0; + /* Make sure it is L2-cachable */ + pte_l1_s_cache_mode |= L1_S_XSCALE_TEX(TEX_XSCALE_T); + pte_l1_s_cache_mode_pt = pte_l1_s_cache_mode &~ L1_S_XSCALE_P; + pte_l2_l_cache_mode |= L2_XSCALE_L_TEX(TEX_XSCALE_T) ; + pte_l2_l_cache_mode_pt = pte_l1_s_cache_mode; + pte_l2_s_cache_mode |= L2_XSCALE_T_TEX(TEX_XSCALE_T); + pte_l2_s_cache_mode_pt = pte_l2_s_cache_mode; + +#else + pmap_copy_page_func = pmap_copy_page_xscale; + pmap_copy_page_offs_func = pmap_copy_page_offs_xscale; + pmap_zero_page_func = pmap_zero_page_xscale; +#endif + + /* + * Disable ECC protection of page table access, for now. + */ + __asm __volatile("mrc p15, 0, %0, c1, c0, 1" : "=r" (auxctl)); + auxctl &= ~XSCALE_AUXCTL_P; + __asm __volatile("mcr p15, 0, %0, c1, c0, 1" : : "r" (auxctl)); +} + +/* + * xscale_setup_minidata: + * + * Set up the mini-data cache clean area. We require the + * caller to allocate the right amount of physically and + * virtually contiguous space. + */ +extern vm_offset_t xscale_minidata_clean_addr; +extern vm_size_t xscale_minidata_clean_size; /* already initialized */ +void +xscale_setup_minidata(vm_offset_t l1pt, vm_offset_t va, vm_paddr_t pa) +{ + pd_entry_t *pde = (pd_entry_t *) l1pt; + pt_entry_t *pte; + vm_size_t size; + uint32_t auxctl; + + xscale_minidata_clean_addr = va; + + /* Round it to page size. */ + size = (xscale_minidata_clean_size + L2_S_OFFSET) & L2_S_FRAME; + + for (; size != 0; + va += L2_S_SIZE, pa += L2_S_SIZE, size -= L2_S_SIZE) { + pte = (pt_entry_t *) kernel_pt_lookup( + pde[L1_IDX(va)] & L1_C_ADDR_MASK); + if (pte == NULL) + panic("xscale_setup_minidata: can't find L2 table for " + "VA 0x%08x", (u_int32_t) va); + pte[l2pte_index(va)] = + L2_S_PROTO | pa | L2_S_PROT(PTE_KERNEL, VM_PROT_READ) | + L2_C | L2_XSCALE_T_TEX(TEX_XSCALE_X); + } + + /* + * Configure the mini-data cache for write-back with + * read/write-allocate. + * + * NOTE: In order to reconfigure the mini-data cache, we must + * make sure it contains no valid data! In order to do that, + * we must issue a global data cache invalidate command! + * + * WE ASSUME WE ARE RUNNING UN-CACHED WHEN THIS ROUTINE IS CALLED! + * THIS IS VERY IMPORTANT! + */ + + /* Invalidate data and mini-data. */ + __asm __volatile("mcr p15, 0, %0, c7, c6, 0" : : "r" (0)); + __asm __volatile("mrc p15, 0, %0, c1, c0, 1" : "=r" (auxctl)); + auxctl = (auxctl & ~XSCALE_AUXCTL_MD_MASK) | XSCALE_AUXCTL_MD_WB_RWA; + __asm __volatile("mcr p15, 0, %0, c1, c0, 1" : : "r" (auxctl)); +} +#endif + /* * Allocate an L1 translation table for the specified pmap. * This is called at pmap creation time. @@ -3781,7 +3955,7 @@ pmap_remove(pmap_t pm, vm_offset_t sva, vm_offset_t eva) * StrongARM accesses to non-cached pages are non-burst making writing * _any_ bulk data very slow. */ -#if ARM_MMU_GENERIC != 0 +#if ARM_MMU_GENERIC != 0 || defined(CPU_XSCALE_CORE3) void pmap_zero_page_generic(vm_paddr_t phys, int off, int size) { @@ -3810,6 +3984,77 @@ pmap_zero_page_generic(vm_paddr_t phys, int off, int size) } #endif /* ARM_MMU_GENERIC != 0 */ +#if ARM_MMU_XSCALE == 1 +void +pmap_zero_page_xscale(vm_paddr_t phys, int off, int size) +{ + + if (_arm_bzero && size >= _min_bzero_size && + _arm_bzero((void *)(phys + off), size, IS_PHYSICAL) == 0) + return; + + mtx_lock(&cmtx); + /* + * Hook in the page, zero it, and purge the cache for that + * zeroed page. Invalidate the TLB as needed. + */ + *cdst_pte = L2_S_PROTO | phys | + L2_S_PROT(PTE_KERNEL, VM_PROT_WRITE) | + L2_C | L2_XSCALE_T_TEX(TEX_XSCALE_X); /* mini-data */ + PTE_SYNC(cdst_pte); + cpu_tlb_flushD_SE(cdstp); + cpu_cpwait(); + if (off || size != PAGE_SIZE) + bzero((void *)(cdstp + off), size); + else + bzero_page(cdstp); + mtx_unlock(&cmtx); + xscale_cache_clean_minidata(); +} + +/* + * Change the PTEs for the specified kernel mappings such that they + * will use the mini data cache instead of the main data cache. + */ +void +pmap_use_minicache(vm_offset_t va, vm_size_t size) +{ + struct l2_bucket *l2b; + pt_entry_t *ptep, *sptep, pte; + vm_offset_t next_bucket, eva; + +#if (ARM_NMMUS > 1) || defined(CPU_XSCALE_CORE3) + if (xscale_use_minidata == 0) + return; +#endif + + eva = va + size; + + while (va < eva) { + next_bucket = L2_NEXT_BUCKET(va); + if (next_bucket > eva) + next_bucket = eva; + + l2b = pmap_get_l2_bucket(kernel_pmap, va); + + sptep = ptep = &l2b->l2b_kva[l2pte_index(va)]; + + while (va < next_bucket) { + pte = *ptep; + if (!l2pte_minidata(pte)) { + cpu_dcache_wbinv_range(va, PAGE_SIZE); + cpu_tlb_flushD_SE(va); + *ptep = pte & ~L2_B; + } + ptep++; + va += PAGE_SIZE; + } + PTE_SYNC_RANGE(sptep, (u_int)(ptep - sptep)); + } + cpu_cpwait(); +} +#endif /* ARM_MMU_XSCALE == 1 */ + /* * pmap_zero_page zeros the specified hardware page by mapping * the page into KVM and using bzero to clear its contents. @@ -3940,7 +4185,7 @@ pmap_clean_page(struct pv_entry *pv, boolean_t is_src) * hook points. The same comment regarding cachability as in * pmap_zero_page also applies here. */ -#if ARM_MMU_GENERIC != 0 +#if ARM_MMU_GENERIC != 0 || defined (CPU_XSCALE_CORE3) void pmap_copy_page_generic(vm_paddr_t src, vm_paddr_t dst) { @@ -4007,6 +4252,72 @@ pmap_copy_page_offs_generic(vm_paddr_t a_phys, vm_offset_t a_offs, } #endif /* ARM_MMU_GENERIC != 0 */ +#if ARM_MMU_XSCALE == 1 +void +pmap_copy_page_xscale(vm_paddr_t src, vm_paddr_t dst) +{ +#if 0 + /* XXX: Only needed for pmap_clean_page(), which is commented out. */ + struct vm_page *src_pg = PHYS_TO_VM_PAGE(src); +#endif + + /* + * Clean the source page. Hold the source page's lock for + * the duration of the copy so that no other mappings can + * be created while we have a potentially aliased mapping. + */ +#if 0 + /* + * XXX: Not needed while we call cpu_dcache_wbinv_all() in + * pmap_copy_page(). + */ + (void) pmap_clean_page(TAILQ_FIRST(&src_pg->md.pv_list), TRUE); +#endif + /* + * Map the pages into the page hook points, copy them, and purge + * the cache for the appropriate page. Invalidate the TLB + * as required. + */ + mtx_lock(&cmtx); + *csrc_pte = L2_S_PROTO | src | + L2_S_PROT(PTE_KERNEL, VM_PROT_READ) | + L2_C | L2_XSCALE_T_TEX(TEX_XSCALE_X); /* mini-data */ + PTE_SYNC(csrc_pte); + *cdst_pte = L2_S_PROTO | dst | + L2_S_PROT(PTE_KERNEL, VM_PROT_WRITE) | + L2_C | L2_XSCALE_T_TEX(TEX_XSCALE_X); /* mini-data */ + PTE_SYNC(cdst_pte); + cpu_tlb_flushD_SE(csrcp); + cpu_tlb_flushD_SE(cdstp); + cpu_cpwait(); + bcopy_page(csrcp, cdstp); + mtx_unlock(&cmtx); + xscale_cache_clean_minidata(); +} + +void +pmap_copy_page_offs_xscale(vm_paddr_t a_phys, vm_offset_t a_offs, + vm_paddr_t b_phys, vm_offset_t b_offs, int cnt) +{ + + mtx_lock(&cmtx); + *csrc_pte = L2_S_PROTO | a_phys | + L2_S_PROT(PTE_KERNEL, VM_PROT_READ) | + L2_C | L2_XSCALE_T_TEX(TEX_XSCALE_X); + PTE_SYNC(csrc_pte); + *cdst_pte = L2_S_PROTO | b_phys | + L2_S_PROT(PTE_KERNEL, VM_PROT_WRITE) | + L2_C | L2_XSCALE_T_TEX(TEX_XSCALE_X); + PTE_SYNC(cdst_pte); + cpu_tlb_flushD_SE(csrcp); + cpu_tlb_flushD_SE(cdstp); + cpu_cpwait(); + bcopy((char *)csrcp + a_offs, (char *)cdstp + b_offs, cnt); + mtx_unlock(&cmtx); + xscale_cache_clean_minidata(); +} +#endif /* ARM_MMU_XSCALE == 1 */ + void pmap_copy_page(vm_page_t src, vm_page_t dst) { diff --git a/sys/arm/arm/trap-v4.c b/sys/arm/arm/trap-v4.c index 88a57d1e1e38..3ee730432e75 100644 --- a/sys/arm/arm/trap-v4.c +++ b/sys/arm/arm/trap-v4.c @@ -514,6 +514,13 @@ dab_align(struct trapframe *tf, u_int fsr, u_int far, struct thread *td, * If pcb_onfault is set, flag the fault and return to the handler. * If the fault occurred in user mode, give the process a SIGBUS. * + * Note: On XScale, FAULT_BUSERR_0, FAULT_BUSERR_1, and FAULT_BUSERR_2 + * can be flagged as imprecise in the FSR. This causes a real headache + * since some of the machine state is lost. In this case, tf->tf_pc + * may not actually point to the offending instruction. In fact, if + * we've taken a double abort fault, it generally points somewhere near + * the top of "data_abort_entry" in exception.S. + * * In all other cases, these data aborts are considered fatal. */ static int @@ -522,6 +529,52 @@ dab_buserr(struct trapframe *tf, u_int fsr, u_int far, struct thread *td, { struct pcb *pcb = td->td_pcb; +#ifdef __XSCALE__ + if ((fsr & FAULT_IMPRECISE) != 0 && + (tf->tf_spsr & PSR_MODE) == PSR_ABT32_MODE) { + /* + * Oops, an imprecise, double abort fault. We've lost the + * r14_abt/spsr_abt values corresponding to the original + * abort, and the spsr saved in the trapframe indicates + * ABT mode. + */ + tf->tf_spsr &= ~PSR_MODE; + + /* + * We use a simple heuristic to determine if the double abort + * happened as a result of a kernel or user mode access. + * If the current trapframe is at the top of the kernel stack, + * the fault _must_ have come from user mode. + */ + if (tf != ((struct trapframe *)pcb->pcb_regs.sf_sp) - 1) { + /* + * Kernel mode. We're either about to die a + * spectacular death, or pcb_onfault will come + * to our rescue. Either way, the current value + * of tf->tf_pc is irrelevant. + */ + tf->tf_spsr |= PSR_SVC32_MODE; + if (pcb->pcb_onfault == NULL) + printf("\nKernel mode double abort!\n"); + } else { + /* + * User mode. We've lost the program counter at the + * time of the fault (not that it was accurate anyway; + * it's not called an imprecise fault for nothing). + * About all we can do is copy r14_usr to tf_pc and + * hope for the best. The process is about to get a + * SIGBUS, so it's probably history anyway. + */ + tf->tf_spsr |= PSR_USR32_MODE; + tf->tf_pc = tf->tf_usr_lr; + } + } + + /* FAR is invalid for imprecise exceptions */ + if ((fsr & FAULT_IMPRECISE) != 0) + far = 0; +#endif /* __XSCALE__ */ + if (pcb->pcb_onfault) { tf->tf_r0 = EFAULT; tf->tf_pc = (register_t)(intptr_t) pcb->pcb_onfault; diff --git a/sys/arm/arm/vm_machdep.c b/sys/arm/arm/vm_machdep.c index febb6de09bee..6fb2b59d3185 100644 --- a/sys/arm/arm/vm_machdep.c +++ b/sys/arm/arm/vm_machdep.c @@ -105,6 +105,11 @@ cpu_fork(struct thread *td1, struct proc *p2, struct thread *td2, int flags) /* Point the pcb to the top of the stack */ pcb2 = (struct pcb *) (td2->td_kstack + td2->td_kstack_pages * PAGE_SIZE) - 1; +#ifdef __XSCALE__ +#ifndef CPU_XSCALE_CORE3 + pmap_use_minicache(td2->td_kstack, td2->td_kstack_pages * PAGE_SIZE); +#endif +#endif #ifdef VFP /* Store actual state of VFP */ if (curthread == td1) { @@ -306,6 +311,12 @@ cpu_thread_alloc(struct thread *td) * the ARM EABI. */ td->td_frame = (struct trapframe *)((caddr_t)td->td_pcb) - 1; + +#ifdef __XSCALE__ +#ifndef CPU_XSCALE_CORE3 + pmap_use_minicache(td->td_kstack, td->td_kstack_pages * PAGE_SIZE); +#endif +#endif } void diff --git a/sys/arm/conf/CRB b/sys/arm/conf/CRB new file mode 100644 index 000000000000..f7d889c6d1fd --- /dev/null +++ b/sys/arm/conf/CRB @@ -0,0 +1,92 @@ +# GENERIC -- Generic kernel configuration file for FreeBSD/arm +# +# For more information on this file, please read the handbook section on +# Kernel Configuration Files: +# +# https://www.FreeBSD.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig-config.html +# +# The handbook is also available locally in /usr/share/doc/handbook +# if you've installed the doc distribution, otherwise always see the +# FreeBSD World Wide Web server (https://www.FreeBSD.org/) for the +# latest information. +# +# An exhaustive list of options and more detailed explanations of the +# device lines is also present in the ../../conf/NOTES and NOTES files. +# If you are in doubt as to the purpose or necessity of a line, check first +# in NOTES. +# +# $FreeBSD$ + +ident CRB + +include "std.arm" +options PHYSADDR=0x00000000 +options KERNVIRTADDR=0xc0200000 # Used in ldscript.arm + +options COUNTS_PER_SEC=400000000 +include "../xscale/i8134x/std.crb" +makeoptions MODULES_OVERRIDE="" + +makeoptions CONF_CFLAGS=-mcpu=xscale +options HZ=100 +#options DEVICE_POLLING + +options SCHED_4BSD # 4BSD scheduler +options INET # InterNETworking +options INET6 # IPv6 communications protocols +options TCP_HHOOK # hhook(9) framework for TCP +options FFS # Berkeley Fast Filesystem +options SOFTUPDATES # Enable FFS soft updates support +options UFS_ACL # Support for access control lists +options UFS_DIRHASH # Improve performance on big directories +options NFSCL # Network Filesystem Client +options NFSD # Network Filesystem Server +options NFSLOCKD # Network Lock Manager +options NFS_ROOT # NFS usable as /, requires NFSCL +#options MSDOSFS # MSDOS Filesystem +options GEOM_PART_BSD # BSD partition scheme +options GEOM_PART_MBR # MBR partition scheme +options TMPFS # Efficient memory filesystem +options CD9660 # ISO 9660 Filesystem +#options PROCFS # Process filesystem (requires PSEUDOFS) +options PSEUDOFS # Pseudo-filesystem framework +options SCSI_DELAY=5000 # Delay (in ms) before probing SCSI +options KTRACE # ktrace(1) support +options SYSVSHM # SYSV-style shared memory +options SYSVMSG # SYSV-style message queues +options SYSVSEM # SYSV-style semaphores +options _KPOSIX_PRIORITY_SCHEDULING # Posix P1003_1B real-time extensions +options KBD_INSTALL_CDEV # install a CDEV entry in /dev +options BOOTP +options BOOTP_NFSROOT +options BOOTP_NFSV3 +options BOOTP_WIRED_TO=em0 +options BOOTP_COMPAT +#options PREEMPTION +device loop +device ether +#device saarm +device miibus +device rl +device em +device uart +device pci + +device ata + +device scbus # SCSI bus (required for ATA/SCSI) +device cd # CD +device da # Direct Access (disks) +device pass # Passthrough device (direct ATA/SCSI access) + +device "7seg" + +# SCSI Controllers + +options XSCALE_CACHE_READ_WRITE_ALLOCATE +device md +device random # Entropy device + +device iopwdog +# Floppy drives + diff --git a/sys/arm/conf/GUMSTIX b/sys/arm/conf/GUMSTIX new file mode 100644 index 000000000000..a6db12e51fef --- /dev/null +++ b/sys/arm/conf/GUMSTIX @@ -0,0 +1,82 @@ +# GUMSTIX -- Custom configuration for the Gumstix Basix and Connex boards from +# gumstix.com +# +# For more information on this file, please read the handbook section on +# Kernel Configuration Files: +# +# https://www.FreeBSD.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig-config.html +# +# The handbook is also available locally in /usr/share/doc/handbook +# if you've installed the doc distribution, otherwise always see the +# FreeBSD World Wide Web server (https://www.FreeBSD.org/) for the +# latest information. +# +# An exhaustive list of options and more detailed explanations of the +# device lines is also present in the ../../conf/NOTES and NOTES files. +# If you are in doubt as to the purpose or necessity of a line, check first +# in NOTES. +# +# $FreeBSD$ + +ident GUMSTIX +include "std.arm" +cpu CPU_XSCALE_PXA2X0 + +# This probably wants to move somewhere else. Maybe we can create a basic +# PXA2X0 config, then make a GUMSTIX config that includes the basic one, +# adds the smc and smcphy devices and pulls in this hints file. +hints "GUMSTIX.hints" + +options PHYSADDR=0xa0000000 +options KERNVIRTADDR=0xc0200000 # Used in ldscript.arm + +include "../xscale/pxa/std.pxa" +makeoptions MODULES_OVERRIDE="" + +options HZ=100 +#options DEVICE_POLLING + +options SCHED_4BSD # 4BSD scheduler +options INET # InterNETworking +#options INET6 # IPv6 communications protocols +options TCP_HHOOK # hhook(9) framework for TCP +options FFS # Berkeley Fast Filesystem +options SOFTUPDATES # Enable FFS soft updates support +options UFS_ACL # Support for access control lists +options UFS_DIRHASH # Improve performance on big directories +options NFSCL # Network Filesystem Client +#options NFSD # Network Filesystem Server +options NFS_ROOT # NFS usable as /, requires NFSCL +options GEOM_PART_BSD # BSD partition scheme +options GEOM_PART_MBR # MBR partition scheme +options TMPFS # Efficient memory filesystem +#options MSDOSFS # MSDOS Filesystem +#options CD9660 # ISO 9660 Filesystem +#options PROCFS # Process filesystem (requires PSEUDOFS) +options PSEUDOFS # Pseudo-filesystem framework +options COMPAT_43 # Compatible with BSD 4.3 [KEEP THIS!] +options SCSI_DELAY=5000 # Delay (in ms) before probing SCSI +options KTRACE # ktrace(1) support +options SYSVSHM # SYSV-style shared memory +options SYSVMSG # SYSV-style message queues +options SYSVSEM # SYSV-style semaphores +options _KPOSIX_PRIORITY_SCHEDULING # Posix P1003_1B real-time extensions +options KBD_INSTALL_CDEV # install a CDEV entry in /dev +options BOOTP +options BOOTP_NFSROOT +options BOOTP_WIRED_TO=smc0 +options BOOTP_COMPAT +options BOOTP_NFSV3 +options BOOTP_BLOCKSIZE=4096 +options PREEMPTION +device loop +device ether +device mii +device mii_bitbang +device smc +device smcphy +device uart +device uart_ns8250 + +device md +device random # Entropy device diff --git a/sys/arm/conf/GUMSTIX-QEMU b/sys/arm/conf/GUMSTIX-QEMU new file mode 100644 index 000000000000..2152da747e55 --- /dev/null +++ b/sys/arm/conf/GUMSTIX-QEMU @@ -0,0 +1,25 @@ +# GUMSTIX-QEMU -- Custom configuration for the QEMU emulated Gumstix target +# +# For more information on this file, please read the handbook section on +# Kernel Configuration Files: +# +# https://www.FreeBSD.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig-config.html +# +# The handbook is also available locally in /usr/share/doc/handbook +# if you've installed the doc distribution, otherwise always see the +# FreeBSD World Wide Web server (https://www.FreeBSD.org/) for the +# latest information. +# +# An exhaustive list of options and more detailed explanations of the +# device lines is also present in the ../../conf/NOTES and NOTES files. +# If you are in doubt as to the purpose or necessity of a line, check first +# in NOTES. +# +# $FreeBSD$ + +include GUMSTIX + +ident GUMSTIX-QEMU + +options QEMU_WORKAROUNDS +nooptions ARM_CACHE_LOCK_ENABLE # QEMU does not implement this diff --git a/sys/arm/conf/GUMSTIX.hints b/sys/arm/conf/GUMSTIX.hints new file mode 100644 index 000000000000..5f4130ebc798 --- /dev/null +++ b/sys/arm/conf/GUMSTIX.hints @@ -0,0 +1,19 @@ +# $FreeBSD$ + +# Make sure we don't trample important bits in the UART registers. +hint.uart.0.ier_mask="0xe0" +hint.uart.0.ier_rxbits="0x1d" +hint.uart.1.ier_mask="0xe0" +hint.uart.1.ier_rxbits="0x1d" +hint.uart.2.ier_mask="0xe0" +hint.uart.2.ier_rxbits="0x1d" + +# SMSC LAN91C111s found on the netCF, netMMC and netDUO boards. +hint.smc.0.at="smi0" +hint.smc.0.mem="0x04000300" +hint.smc.0.size="0x10" +hint.smc.0.irq="100" +hint.smc.1.at="smi0" +hint.smc.1.mem="0x08000300" +hint.smc.1.size="0x10" +hint.smc.1.irq="91" diff --git a/sys/arm/conf/NOTES b/sys/arm/conf/NOTES index 15db46ab66d6..2994fd6cc15d 100644 --- a/sys/arm/conf/NOTES +++ b/sys/arm/conf/NOTES @@ -13,6 +13,9 @@ files "../mv/discovery/files.db78xxx" files "../mv/kirkwood/files.kirkwood" files "../mv/orion/files.db88f5xxx" files "../mv/orion/files.ts7800" +files "../xscale/i8134x/files.crb" +files "../xscale/i8134x/files.i81342" +files "../xscale/pxa/files.pxa" options PHYSADDR=0x00000000 diff --git a/sys/arm/include/armreg.h b/sys/arm/include/armreg.h index ea64fe390de7..38dd347d9de0 100644 --- a/sys/arm/include/armreg.h +++ b/sys/arm/include/armreg.h @@ -108,6 +108,11 @@ /* Next three nybbles are part number */ #define CPU_ID_PARTNO_MASK 0x0000fff0 +/* Intel XScale has sub fields in part number */ +#define CPU_ID_XSCALE_COREGEN_MASK 0x0000e000 /* core generation */ +#define CPU_ID_XSCALE_COREREV_MASK 0x00001c00 /* core revision */ +#define CPU_ID_XSCALE_PRODUCT_MASK 0x000003f0 /* product number */ + /* And finally, the revision number. */ #define CPU_ID_REVISION_MASK 0x0000000f @@ -313,6 +318,18 @@ #define ARM1176_AUXCTL_FSD 0x40000000 /* force speculative ops disable */ #define ARM1176_AUXCTL_FIO 0x80000000 /* low intr latency override */ +/* XScale Auxillary Control Register (CP15 register 1, opcode2 1) */ +#define XSCALE_AUXCTL_K 0x00000001 /* dis. write buffer coalescing */ +#define XSCALE_AUXCTL_P 0x00000002 /* ECC protect page table access */ +/* Note: XSCale core 3 uses those for LLR DCcahce attributes */ +#define XSCALE_AUXCTL_MD_WB_RA 0x00000000 /* mini-D$ wb, read-allocate */ +#define XSCALE_AUXCTL_MD_WB_RWA 0x00000010 /* mini-D$ wb, read/write-allocate */ +#define XSCALE_AUXCTL_MD_WT 0x00000020 /* mini-D$ wt, read-allocate */ +#define XSCALE_AUXCTL_MD_MASK 0x00000030 + +/* Xscale Core 3 only */ +#define XSCALE_AUXCTL_LLR 0x00000400 /* Enable L2 for LLR Cache */ + /* Marvell Extra Features Register (CP15 register 1, opcode2 0) */ #define MV_DC_REPLACE_LOCK 0x80000000 /* Replace DCache Lock */ #define MV_DC_STREAM_ENABLE 0x20000000 /* DCache Streaming Switch */ @@ -393,6 +410,7 @@ #define FAULT_PERM_S 0x0d /* Permission -- Section */ #define FAULT_PERM_P 0x0f /* Permission -- Page */ +#define FAULT_IMPRECISE 0x400 /* Imprecise exception (XSCALE) */ #define FAULT_EXTERNAL 0x400 /* External abort (armv6+) */ #define FAULT_WNR 0x800 /* Write-not-Read access (armv6+) */ diff --git a/sys/arm/include/cpu-v4.h b/sys/arm/include/cpu-v4.h index ee899d12c398..2574f47469ae 100644 --- a/sys/arm/include/cpu-v4.h +++ b/sys/arm/include/cpu-v4.h @@ -95,6 +95,9 @@ _WF1(cp15_cpacr_set, CP15_CPACR(%0)) _RF0(cp15_dfsr_get, CP15_DFSR(%0)) _RF0(cp15_ttbr_get, CP15_TTBR0(%0)) _RF0(cp15_dfar_get, CP15_DFAR(%0)) +/* XScale */ +_RF0(cp15_actlr_get, CP15_ACTLR(%0)) +_WF1(cp15_actlr_set, CP15_ACTLR(%0)) /*CPU id registers */ _RF0(cp15_midr_get, CP15_MIDR(%0)) diff --git a/sys/arm/include/cpufunc.h b/sys/arm/include/cpufunc.h index c614d9dee556..2ed841a1bfdd 100644 --- a/sys/arm/include/cpufunc.h +++ b/sys/arm/include/cpufunc.h @@ -306,7 +306,8 @@ void armv5_ec_idcache_wbinv_range(vm_offset_t, vm_size_t); #endif #if defined(CPU_ARM9) || defined(CPU_ARM9E) || \ - defined(CPU_FA526) + defined(CPU_FA526) || \ + defined(CPU_XSCALE_PXA2X0) || defined(CPU_XSCALE_81342) void armv4_tlb_flushID (void); void armv4_tlb_flushD (void); @@ -316,6 +317,71 @@ void armv4_drain_writebuf (void); void armv4_idcache_inv_all (void); #endif +#if defined(CPU_XSCALE_PXA2X0) || defined(CPU_XSCALE_81342) +void xscale_cpwait (void); + +void xscale_cpu_sleep (int mode); + +u_int xscale_control (u_int clear, u_int bic); + +void xscale_setttb (u_int ttb); + +void xscale_tlb_flushID_SE (u_int va); + +void xscale_cache_flushID (void); +void xscale_cache_flushI (void); +void xscale_cache_flushD (void); +void xscale_cache_flushD_SE (u_int entry); + +void xscale_cache_cleanID (void); +void xscale_cache_cleanD (void); +void xscale_cache_cleanD_E (u_int entry); + +void xscale_cache_clean_minidata (void); + +void xscale_cache_purgeID (void); +void xscale_cache_purgeID_E (u_int entry); +void xscale_cache_purgeD (void); +void xscale_cache_purgeD_E (u_int entry); + +void xscale_cache_syncI (void); +void xscale_cache_cleanID_rng (vm_offset_t start, vm_size_t end); +void xscale_cache_cleanD_rng (vm_offset_t start, vm_size_t end); +void xscale_cache_purgeID_rng (vm_offset_t start, vm_size_t end); +void xscale_cache_purgeD_rng (vm_offset_t start, vm_size_t end); +void xscale_cache_syncI_rng (vm_offset_t start, vm_size_t end); +void xscale_cache_flushD_rng (vm_offset_t start, vm_size_t end); + +void xscale_context_switch (void); + +void xscale_setup (void); +#endif /* CPU_XSCALE_PXA2X0 */ + +#ifdef CPU_XSCALE_81342 + +void xscalec3_l2cache_purge (void); +void xscalec3_cache_purgeID (void); +void xscalec3_cache_purgeD (void); +void xscalec3_cache_cleanID (void); +void xscalec3_cache_cleanD (void); +void xscalec3_cache_syncI (void); + +void xscalec3_cache_purgeID_rng (vm_offset_t start, vm_size_t end); +void xscalec3_cache_purgeD_rng (vm_offset_t start, vm_size_t end); +void xscalec3_cache_cleanID_rng (vm_offset_t start, vm_size_t end); +void xscalec3_cache_cleanD_rng (vm_offset_t start, vm_size_t end); +void xscalec3_cache_syncI_rng (vm_offset_t start, vm_size_t end); + +void xscalec3_l2cache_flush_rng (vm_offset_t, vm_size_t); +void xscalec3_l2cache_clean_rng (vm_offset_t start, vm_size_t end); +void xscalec3_l2cache_purge_rng (vm_offset_t start, vm_size_t end); + + +void xscalec3_setttb (u_int ttb); +void xscalec3_context_switch (void); + +#endif /* CPU_XSCALE_81342 */ + /* * Macros for manipulating CPU interrupts */ diff --git a/sys/arm/include/intr.h b/sys/arm/include/intr.h index 2629325a2d99..9c6425095f3f 100644 --- a/sys/arm/include/intr.h +++ b/sys/arm/include/intr.h @@ -68,7 +68,12 @@ int intr_pic_ipi_setup(u_int, const char *, intr_ipi_handler_t *, void *); #else /* INTRNG */ /* XXX move to std.* files? */ -#if defined(SOC_MV_DISCOVERY) +#ifdef CPU_XSCALE_81342 +#define NIRQ 128 +#elif defined(CPU_XSCALE_PXA2X0) +#include +#define NIRQ IRQ_GPIO_MAX +#elif defined(SOC_MV_DISCOVERY) #define NIRQ 96 #elif defined(CPU_ARM9) || defined(SOC_MV_KIRKWOOD) #define NIRQ 64 diff --git a/sys/arm/include/md_var.h b/sys/arm/include/md_var.h index f62ed1b2a38e..b39220199718 100644 --- a/sys/arm/include/md_var.h +++ b/sys/arm/include/md_var.h @@ -62,7 +62,7 @@ enum cpu_class { CPU_CLASS_ARM10EJ, CPU_CLASS_CORTEXA, CPU_CLASS_KRAIT, - CPU_CLASS_reserved, /* XXX audit and remove ? */ + CPU_CLASS_XSCALE, CPU_CLASS_ARM11J, CPU_CLASS_MARVELL }; diff --git a/sys/arm/include/pmap-v4.h b/sys/arm/include/pmap-v4.h index cfb591cf71c6..39c323a3e491 100644 --- a/sys/arm/include/pmap-v4.h +++ b/sys/arm/include/pmap-v4.h @@ -63,7 +63,13 @@ #define ARM_MMU_GENERIC 0 #endif -#define ARM_NMMUS ARM_MMU_GENERIC +#if (defined(CPU_XSCALE_PXA2X0) || defined(CPU_XSCALE_81342)) +#define ARM_MMU_XSCALE 1 +#else +#define ARM_MMU_XSCALE 0 +#endif + +#define ARM_NMMUS (ARM_MMU_GENERIC + ARM_MMU_XSCALE) #if ARM_NMMUS == 0 && !defined(KLD_MODULE) && defined(_KERNEL) #error ARM_NMMUS is 0 #endif @@ -271,15 +277,35 @@ extern int pmap_needs_pte_sync; */ #define L1_S_CACHE_MASK_generic (L1_S_B|L1_S_C) +#define L1_S_CACHE_MASK_xscale (L1_S_B|L1_S_C|L1_S_XSCALE_TEX(TEX_XSCALE_X)|\ + L1_S_XSCALE_TEX(TEX_XSCALE_T)) + #define L2_L_CACHE_MASK_generic (L2_B|L2_C) +#define L2_L_CACHE_MASK_xscale (L2_B|L2_C|L2_XSCALE_L_TEX(TEX_XSCALE_X) | \ + L2_XSCALE_L_TEX(TEX_XSCALE_T)) + #define L2_S_PROT_U_generic (L2_AP(AP_U)) #define L2_S_PROT_W_generic (L2_AP(AP_W)) #define L2_S_PROT_MASK_generic (L2_S_PROT_U|L2_S_PROT_W) + +#define L2_S_PROT_U_xscale (L2_AP0(AP_U)) +#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_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_C_PROTO_generic (L1_TYPE_C | L1_C_IMP2) +#define L1_C_PROTO_xscale (L1_TYPE_C) + #define L2_L_PROTO (L2_TYPE_L) + #define L2_S_PROTO_generic (L2_TYPE_S) +#define L2_S_PROTO_xscale (L2_TYPE_XSCALE_XS) /* * User-visible names for the ones that vary with MMU class. @@ -312,9 +338,29 @@ extern int pmap_needs_pte_sync; #define L1_S_PROTO L1_S_PROTO_generic #define L1_C_PROTO L1_C_PROTO_generic #define L2_S_PROTO L2_S_PROTO_generic -#endif +#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 +#define L2_S_PROT_MASK L2_S_PROT_MASK_xscale + +#define L1_S_CACHE_MASK L1_S_CACHE_MASK_xscale +#define L2_L_CACHE_MASK L2_L_CACHE_MASK_xscale +#define L2_S_CACHE_MASK L2_S_CACHE_MASK_xscale + +#define L1_S_PROTO L1_S_PROTO_xscale +#define L1_C_PROTO L1_C_PROTO_xscale +#define L2_S_PROTO L2_S_PROTO_xscale + +#endif /* ARM_NMMUS > 1 */ + +#if defined(CPU_XSCALE_81342) +#define CPU_XSCALE_CORE3 +#define PMAP_NEEDS_PTE_SYNC 1 +#define PMAP_INCLUDE_PTE_SYNC +#else #define PMAP_NEEDS_PTE_SYNC 0 +#endif /* * These macros return various bits based on kernel/user and protection. @@ -411,13 +457,27 @@ extern void (*pmap_copy_page_offs_func)(vm_paddr_t a_phys, vm_offset_t a_offs, vm_paddr_t b_phys, vm_offset_t b_offs, int cnt); extern void (*pmap_zero_page_func)(vm_paddr_t, int, int); -#if ARM_MMU_GENERIC != 0 +#if ARM_MMU_GENERIC != 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); void pmap_pte_init_generic(void); #endif /* ARM_MMU_GENERIC != 0 */ +#if ARM_MMU_XSCALE == 1 +void pmap_copy_page_xscale(vm_paddr_t, vm_paddr_t); +void pmap_zero_page_xscale(vm_paddr_t, int, int); + +void pmap_pte_init_xscale(void); + +void xscale_setup_minidata(vm_offset_t, vm_offset_t, vm_offset_t); + +void pmap_use_minicache(vm_offset_t, vm_size_t); +#endif /* ARM_MMU_XSCALE == 1 */ +#if defined(CPU_XSCALE_81342) +#define ARM_HAVE_SUPERSECTIONS +#endif + #define PTE_KERNEL 0 #define PTE_USER 1 #define l1pte_valid(pde) ((pde) != 0) @@ -428,6 +488,9 @@ void pmap_pte_init_generic(void); #define l2pte_index(v) (((v) & L1_S_OFFSET) >> L2_S_SHIFT) #define l2pte_valid(pte) ((pte) != 0) #define l2pte_pa(pte) ((pte) & L2_S_FRAME) +#define l2pte_minidata(pte) (((pte) & \ + (L2_B | L2_C | L2_XSCALE_T_TEX(TEX_XSCALE_X)))\ + == (L2_C | L2_XSCALE_T_TEX(TEX_XSCALE_X))) /* L1 and L2 page table macros */ #define pmap_pde_v(pde) l1pte_valid(*(pde)) diff --git a/sys/arm/include/pmc_mdep.h b/sys/arm/include/pmc_mdep.h index a8e8dced3c4e..dcae9c8cb2e3 100644 --- a/sys/arm/include/pmc_mdep.h +++ b/sys/arm/include/pmc_mdep.h @@ -31,13 +31,15 @@ #ifndef _MACHINE_PMC_MDEP_H_ #define _MACHINE_PMC_MDEP_H_ +#define PMC_MDEP_CLASS_INDEX_XSCALE 1 #define PMC_MDEP_CLASS_INDEX_ARMV7 1 - /* * On the ARM platform we support the following PMCs. * + * XSCALE Intel XScale processors * ARMV7 ARM Cortex-A processors */ +#include #include union pmc_md_op_pmcallocate { @@ -50,6 +52,7 @@ union pmc_md_op_pmcallocate { #ifdef _KERNEL union pmc_md_pmc { + struct pmc_md_xscale_pmc pm_xscale; struct pmc_md_armv7_pmc pm_armv7; }; @@ -77,6 +80,8 @@ union pmc_md_pmc { /* * Prototypes */ +struct pmc_mdep *pmc_xscale_initialize(void); +void pmc_xscale_finalize(struct pmc_mdep *_md); struct pmc_mdep *pmc_armv7_initialize(void); void pmc_armv7_finalize(struct pmc_mdep *_md); #endif /* _KERNEL */ diff --git a/sys/arm/include/pte-v4.h b/sys/arm/include/pte-v4.h index 90380ab10b89..7102902c18f7 100644 --- a/sys/arm/include/pte-v4.h +++ b/sys/arm/include/pte-v4.h @@ -180,6 +180,9 @@ typedef pt_entry_t pt2_entry_t; /* compatibility with v6 */ #define L1_S_APX (1 << 15) #define L1_SHARED (1 << 16) +#define L1_S_XSCALE_P 0x00000200 /* ECC enable for this section */ +#define L1_S_XSCALE_TEX(x) ((x) << 12) /* Type Extension */ + #define L1_S_SUPERSEC ((1) << 18) /* Section is a super-section. */ /* L1 Coarse Descriptor */ @@ -190,6 +193,8 @@ typedef pt_entry_t pt2_entry_t; /* compatibility with v6 */ #define L1_C_DOM_MASK L1_C_DOM(0xf) #define L1_C_ADDR_MASK 0xfffffc00 /* phys address of L2 Table */ +#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 */ @@ -198,6 +203,8 @@ typedef pt_entry_t pt2_entry_t; /* compatibility with v6 */ #define L1_F_DOM_MASK L1_F_DOM(0xf) #define L1_F_ADDR_MASK 0xfffff000 /* phys address of L2 Table */ +#define L1_F_XSCALE_P 0x00000200 /* ECC enable for this section */ + /* * ARM L2 Descriptors */ @@ -207,6 +214,15 @@ typedef pt_entry_t pt2_entry_t; /* compatibility with v6 */ #define L2_TYPE_S 0x02 /* Small Page */ #define L2_TYPE_T 0x03 /* Tiny Page */ #define L2_TYPE_MASK 0x03 /* mask of type bits */ + + /* + * This L2 Descriptor type is available on XScale processors + * when using a Coarse L1 Descriptor. The Extended Small + * Descriptor has the same format as the XScale Tiny Descriptor, + * but describes a 4K page, rather than a 1K page. + */ +#define L2_TYPE_XSCALE_XS 0x03 /* XScale Extended Small Page */ + #define L2_B 0x00000004 /* Bufferable page */ #define L2_C 0x00000008 /* Cacheable page */ #define L2_AP0(x) ((x) << 4) /* access permissions (sp 0) */ @@ -222,6 +238,10 @@ typedef pt_entry_t pt2_entry_t; /* compatibility with v6 */ #define L2_S_TEX_MASK (0x7 << 6) /* Type Extension */ #define L2_S_TEX(x) (((x) & 0x7) << 6) +#define L2_XSCALE_L_TEX(x) ((x) << 12) /* Type Extension */ +#define L2_XSCALE_L_S(x) (1 << 15) /* Shared */ +#define L2_XSCALE_T_TEX(x) ((x) << 6) /* Type Extension */ + /* * Access Permissions for L1 and L2 Descriptors. */ @@ -248,6 +268,30 @@ typedef pt_entry_t pt2_entry_t; /* compatibility with v6 */ #define DOMAIN_RESERVED 0x02 /* reserved */ #define DOMAIN_MANAGER 0x03 /* manager */ +/* + * Type Extension bits for XScale processors. + * + * Behavior of C and B when X == 0: + * + * C B Cacheable Bufferable Write Policy Line Allocate Policy + * 0 0 N N - - + * 0 1 N Y - - + * 1 0 Y Y Write-through Read Allocate + * 1 1 Y Y Write-back Read Allocate + * + * Behavior of C and B when X == 1: + * C B Cacheable Bufferable Write Policy Line Allocate Policy + * 0 0 - - - - DO NOT USE + * 0 1 N Y - - + * 1 0 Mini-Data - - - + * 1 1 Y Y Write-back R/W Allocate + */ +#define TEX_XSCALE_X 0x01 /* X modifies C and B */ +#define TEX_XSCALE_E 0x02 +#define TEX_XSCALE_T 0x04 + +/* Xscale core 3 */ + /* * * Cache attributes with L2 present, S = 0 diff --git a/sys/arm/xscale/i8134x/crb_machdep.c b/sys/arm/xscale/i8134x/crb_machdep.c new file mode 100644 index 000000000000..93687efd7e13 --- /dev/null +++ b/sys/arm/xscale/i8134x/crb_machdep.c @@ -0,0 +1,333 @@ +/* $NetBSD: hpc_machdep.c,v 1.70 2003/09/16 08:18:22 agc Exp $ */ + +/*- + * SPDX-License-Identifier: BSD-4-Clause + * + * Copyright (c) 1994-1998 Mark Brinicombe. + * Copyright (c) 1994 Brini. + * All rights reserved. + * + * This code is derived from software written for Brini by Mark Brinicombe + * + * 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 Brini. + * 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 BRINI ``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 BRINI 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. + * + * RiscBSD kernel project + * + * machdep.c + * + * Machine dependent functions for kernel setup + * + * This file needs a lot of work. + * + * Created : 17/09/94 + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_kstack_pages.h" + +#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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include /* For i80321_calibrate_delay() */ + +#include +#include +#include + + +#define KERNEL_PT_SYS 0 /* Page table for mapping proc0 zero page */ +#define KERNEL_PT_IOPXS 1 +#define KERNEL_PT_BEFOREKERN 2 +#define KERNEL_PT_AFKERNEL 3 /* L2 table for mapping after kernel */ +#define KERNEL_PT_AFKERNEL_NUM 9 + +/* 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) + +struct pv_addr kernel_pt_table[NUM_KERNEL_PTS]; + +/* Physical and virtual addresses for some global pages */ + +struct pv_addr systempage; +struct pv_addr msgbufpv; +struct pv_addr irqstack; +struct pv_addr undstack; +struct pv_addr abtstack; +struct pv_addr kernelstack; + +/* Static device mappings. */ +static const struct devmap_entry iq81342_devmap[] = { + { + IOP34X_VADDR, + IOP34X_HWADDR, + IOP34X_SIZE, + }, + { + /* + * Cheat and map a whole section, this will bring + * both PCI-X and PCI-E outbound I/O + */ + rounddown2(IOP34X_PCIX_OIOBAR_VADDR, 0x100000), + rounddown2(IOP34X_PCIX_OIOBAR, 0x100000), + 0x100000, + }, + { + IOP34X_PCE1_VADDR, + IOP34X_PCE1, + IOP34X_PCE1_SIZE, + }, + { + 0, + 0, + 0, + } +}; + +#define SDRAM_START 0x00000000 + +extern vm_offset_t xscale_cache_clean_addr; + +void * +initarm(struct arm_boot_params *abp) +{ + struct pv_addr kernel_l1pt; + struct pv_addr dpcpu; + int loop, i; + u_int l1pagetable; + vm_offset_t freemempos; + vm_offset_t freemem_pt; + vm_offset_t afterkern; + vm_offset_t freemem_after; + vm_offset_t lastaddr; + uint32_t memsize, memstart; + + lastaddr = parse_boot_param(abp); + arm_physmem_kernaddr = abp->abp_physaddr; + set_cpufuncs(); + pcpu_init(pcpup, 0, sizeof(struct pcpu)); + PCPU_SET(curthread, &thread0); + + /* Do basic tuning, hz etc */ + init_param1(); + + freemempos = 0x00200000; + /* Define a macro to simplify memory allocation */ +#define valloc_pages(var, np) \ + alloc_pages((var).pv_pa, (np)); \ + (var).pv_va = (var).pv_pa + 0xc0000000; + +#define alloc_pages(var, np) \ + freemempos -= (np * PAGE_SIZE); \ + (var) = freemempos; \ + memset((char *)(var), 0, ((np) * PAGE_SIZE)); + + while (((freemempos - L1_TABLE_SIZE) & (L1_TABLE_SIZE - 1)) != 0) + freemempos -= PAGE_SIZE; + valloc_pages(kernel_l1pt, L1_TABLE_SIZE / PAGE_SIZE); + for (loop = 0; loop < NUM_KERNEL_PTS; ++loop) { + if (!(loop % (PAGE_SIZE / L2_TABLE_SIZE_REAL))) { + valloc_pages(kernel_pt_table[loop], + L2_TABLE_SIZE / PAGE_SIZE); + } else { + kernel_pt_table[loop].pv_pa = freemempos + + (loop % (PAGE_SIZE / L2_TABLE_SIZE_REAL)) * + L2_TABLE_SIZE_REAL; + kernel_pt_table[loop].pv_va = + kernel_pt_table[loop].pv_pa + 0xc0000000; + } + } + freemem_pt = freemempos; + freemempos = 0x00100000; + /* + * Allocate a page for the system page mapped to V0x00000000 + * This page will just contain the system vectors and can be + * shared by all processes. + */ + valloc_pages(systempage, 1); + + /* Allocate dynamic per-cpu area. */ + valloc_pages(dpcpu, DPCPU_SIZE / PAGE_SIZE); + dpcpu_init((void *)dpcpu.pv_va, 0); + + /* Allocate stacks for all modes */ + valloc_pages(irqstack, IRQ_STACK_SIZE); + valloc_pages(abtstack, ABT_STACK_SIZE); + valloc_pages(undstack, UND_STACK_SIZE); + valloc_pages(kernelstack, kstack_pages); + valloc_pages(msgbufpv, round_page(msgbufsize) / PAGE_SIZE); + /* + * Now we start construction of the L1 page table + * We start by mapping the L2 page tables into the L1. + * This means that we can replace L1 mappings later on if necessary + */ + l1pagetable = kernel_l1pt.pv_va; + + /* Map the L2 pages tables in the L1 page table */ + pmap_link_l2pt(l1pagetable, rounddown2(ARM_VECTORS_HIGH, 0x00100000), + &kernel_pt_table[KERNEL_PT_SYS]); + pmap_map_chunk(l1pagetable, KERNBASE, SDRAM_START, 0x100000, + VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); + + pmap_map_chunk(l1pagetable, KERNBASE + 0x100000, SDRAM_START + 0x100000, + 0x100000, VM_PROT_READ|VM_PROT_WRITE, PTE_PAGETABLE); + + pmap_map_chunk(l1pagetable, KERNBASE + 0x200000, SDRAM_START + 0x200000, + rounddown2(((uint32_t)(lastaddr) - KERNBASE - 0x200000) + L1_S_SIZE, L1_S_SIZE), + VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); + freemem_after = rounddown2((int)lastaddr + PAGE_SIZE, PAGE_SIZE); + afterkern = round_page(rounddown2((vm_offset_t)lastaddr + L1_S_SIZE, L1_S_SIZE)); + for (i = 0; i < KERNEL_PT_AFKERNEL_NUM; i++) { + pmap_link_l2pt(l1pagetable, afterkern + i * 0x00100000, + &kernel_pt_table[KERNEL_PT_AFKERNEL + i]); + } + + + /* Map the vector page. */ + pmap_map_entry(l1pagetable, ARM_VECTORS_HIGH, systempage.pv_pa, + VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); + devmap_bootstrap(l1pagetable, iq81342_devmap); + /* + * Give the XScale global cache clean code an appropriately + * sized chunk of unmapped VA space starting at 0xff000000 + * (our device mappings end before this address). + */ + xscale_cache_clean_addr = 0xff000000U; + + cpu_domains((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT); + cpu_setttb(kernel_l1pt.pv_pa); + cpu_tlb_flushID(); + cpu_domains(DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)); + /* + * Pages were allocated during the secondary bootstrap for the + * stacks for different CPU modes. + * We must now set the r13 registers in the different CPU modes to + * point to these stacks. + * Since the ARM stacks use STMFD etc. we must set r13 to the top end + * of the stack memory. + */ + + set_stackptrs(0); + + /* + * We must now clean the cache again.... + * Cleaning may be done by reading new data to displace any + * dirty data in the cache. This will have happened in cpu_setttb() + * but since we are boot strapping the addresses used for the read + * may have just been remapped and thus the cache could be out + * of sync. A re-clean after the switch will cure this. + * After booting there are no gross relocations of the kernel thus + * this problem will not occur after initarm(). + */ + cpu_idcache_wbinv_all(); + cpu_setup(); + + i80321_calibrate_delay(); + i81342_sdram_bounds(arm_base_bs_tag, IOP34X_VADDR, &memstart, &memsize); + physmem = memsize / PAGE_SIZE; + cninit(); + /* Set stack for exception handlers */ + + undefined_init(); + + init_proc0(kernelstack.pv_va); + + arm_vector_init(ARM_VECTORS_HIGH, ARM_VEC_ALL); + + pmap_curmaxkvaddr = afterkern + PAGE_SIZE; + + vm_max_kernel_address = 0xe0000000; + pmap_bootstrap(pmap_curmaxkvaddr, &kernel_l1pt); + msgbufp = (void*)msgbufpv.pv_va; + msgbufinit(msgbufp, msgbufsize); + mutex_init(); + + /* + * Add the physical ram we have available. + * + * Exclude the kernel (and all the things we allocated which immediately + * follow the kernel) from the VM allocation pool but not from crash + * dumps. virtual_avail is a global variable which tracks the kva we've + * "allocated" while setting up pmaps. + * + * Prepare the list of physical memory available to the vm subsystem. + */ + arm_physmem_hardware_region(SDRAM_START, memsize); + arm_physmem_exclude_region(freemem_pt, abp->abp_physaddr - + freemem_pt, EXFLAG_NOALLOC); + arm_physmem_exclude_region(freemempos, abp->abp_physaddr - 0x100000 - + freemempos, EXFLAG_NOALLOC); + arm_physmem_exclude_region(abp->abp_physaddr, + virtual_avail - KERNVIRTADDR, EXFLAG_NOALLOC); + arm_physmem_init_kernel_globals(); + + init_param2(physmem); + kdb_init(); + return ((void *)(kernelstack.pv_va + USPACE_SVC_STACK_TOP - + sizeof(struct pcb))); +} diff --git a/sys/arm/xscale/i8134x/files.crb b/sys/arm/xscale/i8134x/files.crb new file mode 100644 index 000000000000..25398af60f95 --- /dev/null +++ b/sys/arm/xscale/i8134x/files.crb @@ -0,0 +1,3 @@ +# $FreeBSD$ +arm/xscale/i8134x/crb_machdep.c standard +arm/xscale/i8134x/iq81342_7seg.c optional 7seg diff --git a/sys/arm/xscale/i8134x/files.i81342 b/sys/arm/xscale/i8134x/files.i81342 new file mode 100644 index 000000000000..63c715cb4be7 --- /dev/null +++ b/sys/arm/xscale/i8134x/files.i81342 @@ -0,0 +1,12 @@ +# $FreeBSD$ +arm/arm/bus_space_base.c standard +arm/xscale/i8134x/i80321_timer.c standard +arm/xscale/i8134x/i80321_wdog.c optional iopwdog +arm/xscale/i8134x/i81342.c standard +arm/xscale/i8134x/i81342_mcu.c standard +arm/xscale/i8134x/i81342_pci.c optional pci +arm/xscale/i8134x/i81342_space.c standard +arm/xscale/i8134x/obio.c standard +arm/xscale/i8134x/uart_bus_i81342.c optional uart +arm/xscale/i8134x/uart_cpu_i81342.c optional uart +dev/uart/uart_dev_ns8250.c optional uart diff --git a/sys/arm/xscale/i8134x/i80321_timer.c b/sys/arm/xscale/i8134x/i80321_timer.c new file mode 100644 index 000000000000..5dc650568c0a --- /dev/null +++ b/sys/arm/xscale/i8134x/i80321_timer.c @@ -0,0 +1,486 @@ +/* $NetBSD: i80321_timer.c,v 1.7 2003/07/27 04:52:28 thorpej Exp $ */ + +/*- + * Copyright (c) 2001, 2002 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. + */ + +/* + * Timer/clock support for the Intel i80321 I/O processor. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CPU_XSCALE_81342 +#define ICU_INT_TIMER0 (8) /* XXX: Can't include i81342reg.h because + definitions overrides the ones from i80321reg.h + */ +#endif +#include "opt_timer.h" + +void (*i80321_hardclock_hook)(void) = NULL; +struct i80321_timer_softc { + device_t dev; +} timer_softc; + + +static unsigned i80321_timer_get_timecount(struct timecounter *tc); + + +static uint32_t counts_per_hz; + +#if defined(XSCALE_DISABLE_CCNT) || defined(CPU_XSCALE_81342) +static uint32_t offset; +static uint32_t last = -1; +#endif + +static int ticked = 0; + +#ifndef COUNTS_PER_SEC +#define COUNTS_PER_SEC 200000000 /* 200MHz */ +#endif + +#define COUNTS_PER_USEC (COUNTS_PER_SEC / 1000000) + +static struct timecounter i80321_timer_timecounter = { + i80321_timer_get_timecount, /* get_timecount */ + NULL, /* no poll_pps */ + ~0u, /* counter_mask */ +#if defined(XSCALE_DISABLE_CCNT) || defined(CPU_XSCALE_81342) + COUNTS_PER_SEC, +#else + COUNTS_PER_SEC * 3, /* frequency */ +#endif + "i80321 timer", /* name */ + 1000 /* quality */ +}; + +static int +i80321_timer_probe(device_t dev) +{ + + device_set_desc(dev, "i80321 timer"); + return (0); +} + +static int +i80321_timer_attach(device_t dev) +{ + timer_softc.dev = dev; + + return (0); +} + +static device_method_t i80321_timer_methods[] = { + DEVMETHOD(device_probe, i80321_timer_probe), + DEVMETHOD(device_attach, i80321_timer_attach), + {0, 0}, +}; + +static driver_t i80321_timer_driver = { + "itimer", + i80321_timer_methods, + sizeof(struct i80321_timer_softc), +}; +static devclass_t i80321_timer_devclass; + +DRIVER_MODULE(itimer, iq, i80321_timer_driver, i80321_timer_devclass, 0, 0); + +int clockhandler(void *); + + +static __inline uint32_t +tmr1_read(void) +{ + uint32_t rv; + +#ifdef CPU_XSCALE_81342 + __asm __volatile("mrc p6, 0, %0, c1, c9, 0" +#else + __asm __volatile("mrc p6, 0, %0, c1, c1, 0" +#endif + : "=r" (rv)); + return (rv); +} + +static __inline void +tmr1_write(uint32_t val) +{ + + +#ifdef CPU_XSCALE_81342 + __asm __volatile("mcr p6, 0, %0, c1, c9, 0" +#else + __asm __volatile("mcr p6, 0, %0, c1, c1, 0" +#endif + : + : "r" (val)); +} + +static __inline uint32_t +tcr1_read(void) +{ + uint32_t rv; + +#ifdef CPU_XSCALE_81342 + __asm __volatile("mrc p6, 0, %0, c3, c9, 0" +#else + __asm __volatile("mrc p6, 0, %0, c3, c1, 0" +#endif + : "=r" (rv)); + return (rv); +} +static __inline void +tcr1_write(uint32_t val) +{ + +#ifdef CPU_XSCALE_81342 + __asm __volatile("mcr p6, 0, %0, c3, c9, 0" +#else + __asm __volatile("mcr p6, 0, %0, c3, c1, 0" +#endif + : + : "r" (val)); +} + +static __inline void +trr1_write(uint32_t val) +{ + +#ifdef CPU_XSCALE_81342 + __asm __volatile("mcr p6, 0, %0, c5, c9, 0" +#else + __asm __volatile("mcr p6, 0, %0, c5, c1, 0" +#endif + : + : "r" (val)); +} + +static __inline uint32_t +tmr0_read(void) +{ + uint32_t rv; + +#ifdef CPU_XSCALE_81342 + __asm __volatile("mrc p6, 0, %0, c0, c9, 0" +#else + __asm __volatile("mrc p6, 0, %0, c0, c1, 0" +#endif + : "=r" (rv)); + return (rv); +} + +static __inline void +tmr0_write(uint32_t val) +{ + +#ifdef CPU_XSCALE_81342 + __asm __volatile("mcr p6, 0, %0, c0, c9, 0" +#else + __asm __volatile("mcr p6, 0, %0, c0, c1, 0" +#endif + : + : "r" (val)); +} + +static __inline uint32_t +tcr0_read(void) +{ + uint32_t rv; + +#ifdef CPU_XSCALE_81342 + __asm __volatile("mrc p6, 0, %0, c2, c9, 0" +#else + __asm __volatile("mrc p6, 0, %0, c2, c1, 0" +#endif + : "=r" (rv)); + return (rv); +} +static __inline void +tcr0_write(uint32_t val) +{ + +#ifdef CPU_XSCALE_81342 + __asm __volatile("mcr p6, 0, %0, c2, c9, 0" +#else + __asm __volatile("mcr p6, 0, %0, c2, c1, 0" +#endif + : + : "r" (val)); +} + +static __inline void +trr0_write(uint32_t val) +{ + +#ifdef CPU_XSCALE_81342 + __asm __volatile("mcr p6, 0, %0, c4, c9, 0" +#else + __asm __volatile("mcr p6, 0, %0, c4, c1, 0" +#endif + : + : "r" (val)); +} + +static __inline void +tisr_write(uint32_t val) +{ + +#ifdef CPU_XSCALE_81342 + __asm __volatile("mcr p6, 0, %0, c6, c9, 0" +#else + __asm __volatile("mcr p6, 0, %0, c6, c1, 0" +#endif + : + : "r" (val)); +} + +static __inline uint32_t +tisr_read(void) +{ + int ret; + +#ifdef CPU_XSCALE_81342 + __asm __volatile("mrc p6, 0, %0, c6, c9, 0" : "=r" (ret)); +#else + __asm __volatile("mrc p6, 0, %0, c6, c1, 0" : "=r" (ret)); +#endif + return (ret); +} + +static unsigned +i80321_timer_get_timecount(struct timecounter *tc) +{ +#if defined(XSCALE_DISABLE_CCNT) || defined(CPU_XSCALE_81342) + uint32_t cur = tcr0_read(); + + if (cur > last && last != -1) { + offset += counts_per_hz; + if (ticked > 0) + ticked--; + } + if (ticked) { + offset += ticked * counts_per_hz; + ticked = 0; + } + return (counts_per_hz - cur + offset); +#else + uint32_t ret; + + __asm __volatile("mrc p14, 0, %0, c1, c0, 0\n" + : "=r" (ret)); + return (ret); +#endif +} + +/* + * i80321_calibrate_delay: + * + * Calibrate the delay loop. + */ +void +i80321_calibrate_delay(void) +{ + + /* + * Just use hz=100 for now -- we'll adjust it, if necessary, + * in cpu_initclocks(). + */ + counts_per_hz = COUNTS_PER_SEC / 100; + + tmr0_write(0); /* stop timer */ + tisr_write(TISR_TMR0); /* clear interrupt */ + trr0_write(counts_per_hz); /* reload value */ + tcr0_write(counts_per_hz); /* current value */ + + tmr0_write(TMRx_ENABLE|TMRx_RELOAD|TMRx_CSEL_CORE); +} + +/* + * cpu_initclocks: + * + * Initialize the clock and get them going. + */ +void +cpu_initclocks(void) +{ + u_int oldirqstate; + struct resource *irq; + int rid = 0; + void *ihl; + device_t dev = timer_softc.dev; + + if (hz < 50 || COUNTS_PER_SEC % hz) { + printf("Cannot get %d Hz clock; using 100 Hz\n", hz); + hz = 100; + } + tick = 1000000 / hz; /* number of microseconds between interrupts */ + + /* + * We only have one timer available; stathz and profhz are + * always left as 0 (the upper-layer clock code deals with + * this situation). + */ + if (stathz != 0) + printf("Cannot get %d Hz statclock\n", stathz); + stathz = 0; + + if (profhz != 0) + printf("Cannot get %d Hz profclock\n", profhz); + profhz = 0; + + /* Report the clock frequency. */ + + oldirqstate = disable_interrupts(PSR_I); + + irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, +#ifdef CPU_XSCALE_81342 + ICU_INT_TIMER0, ICU_INT_TIMER0, +#else + ICU_INT_TMR0, ICU_INT_TMR0, +#endif + 1, RF_ACTIVE); + if (!irq) + panic("Unable to setup the clock irq handler.\n"); + else + bus_setup_intr(dev, irq, INTR_TYPE_CLK, clockhandler, NULL, + NULL, &ihl); + tmr0_write(0); /* stop timer */ + tisr_write(TISR_TMR0); /* clear interrupt */ + + counts_per_hz = COUNTS_PER_SEC / hz; + + trr0_write(counts_per_hz); /* reload value */ + tcr0_write(counts_per_hz); /* current value */ + tmr0_write(TMRx_ENABLE|TMRx_RELOAD|TMRx_CSEL_CORE); + + tc_init(&i80321_timer_timecounter); + restore_interrupts(oldirqstate); + rid = 0; +#if !defined(XSCALE_DISABLE_CCNT) && !defined(CPU_XSCALE_81342) + /* Enable the clock count register. */ + __asm __volatile("mrc p14, 0, %0, c0, c0, 0\n" : "=r" (rid)); + rid &= ~(1 << 3); + rid |= (1 << 2) | 1; + __asm __volatile("mcr p14, 0, %0, c0, c0, 0\n" + : : "r" (rid)); +#endif +} + + +/* + * DELAY: + * + * Delay for at least N microseconds. + */ +void +DELAY(int n) +{ + uint32_t cur, last, delta, usecs; + + TSENTER(); + /* + * This works by polling the timer and counting the + * number of microseconds that go by. + */ + last = tcr0_read(); + delta = usecs = 0; + + while (n > usecs) { + cur = tcr0_read(); + + /* Check to see if the timer has wrapped around. */ + if (last < cur) + delta += (last + (counts_per_hz - cur)); + else + delta += (last - cur); + + last = cur; + + if (delta >= COUNTS_PER_USEC) { + usecs += delta / COUNTS_PER_USEC; + delta %= COUNTS_PER_USEC; + } + } + TSEXIT(); +} + +/* + * clockhandler: + * + * Handle the hardclock interrupt. + */ +int +clockhandler(void *arg) +{ + struct trapframe *frame = arg; + + ticked++; + tisr_write(TISR_TMR0); + hardclock(TRAPF_USERMODE(frame), TRAPF_PC(frame)); + + if (i80321_hardclock_hook != NULL) + (*i80321_hardclock_hook)(); + return (FILTER_HANDLED); +} + +void +cpu_startprofclock(void) +{ +} + +void +cpu_stopprofclock(void) +{ + +} diff --git a/sys/arm/xscale/i8134x/i80321_wdog.c b/sys/arm/xscale/i8134x/i80321_wdog.c new file mode 100644 index 000000000000..72f0fd8511af --- /dev/null +++ b/sys/arm/xscale/i8134x/i80321_wdog.c @@ -0,0 +1,153 @@ +/* $NetBSD: i80321_wdog.c,v 1.6 2003/07/15 00:24:54 lukem Exp $ */ + +/*- + * Copyright (c) 2005 Olivier Houchard + * Copyright (c) 2002 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. + */ + +/* + * Watchdog timer support for the Intel i80321 I/O processor. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + + +struct iopwdog_softc { + device_t dev; + int armed; + int wdog_period; +}; + +static __inline void +wdtcr_write(uint32_t val) +{ + +#ifdef CPU_XSCALE_81342 + __asm __volatile("mcr p6, 0, %0, c7, c9, 0" +#else + __asm __volatile("mcr p6, 0, %0, c7, c1, 0" +#endif + : + : "r" (val)); +} + +static void +iopwdog_tickle(void *arg) +{ + struct iopwdog_softc *sc = arg; + + if (!sc->armed) + return; + wdtcr_write(WDTCR_ENABLE1); + wdtcr_write(WDTCR_ENABLE2); +} + +static int +iopwdog_probe(device_t dev) +{ + struct iopwdog_softc *sc = device_get_softc(dev); + char buf[128]; + + /* + * XXX Should compute the period based on processor speed. + * For a 600MHz XScale core, the wdog must be tickled approx. + * every 7 seconds. + */ + + sc->wdog_period = 7; + sprintf(buf, "i80321 Watchdog, must be tickled every %d seconds", + sc->wdog_period); + device_set_desc_copy(dev, buf); + + return (0); +} + +static void +iopwdog_watchdog_fn(void *private, u_int cmd, int *error) +{ + struct iopwdog_softc *sc = private; + + cmd &= WD_INTERVAL; + if (cmd > 0 && cmd <= 63 + && (uint64_t)1<wdog_period * 1000000000) { + /* Valid value -> Enable watchdog */ + iopwdog_tickle(sc); + sc->armed = 1; + *error = 0; + } else { + /* Can't disable this watchdog! */ + if (sc->armed) + *error = EOPNOTSUPP; + } +} + +static int +iopwdog_attach(device_t dev) +{ + struct iopwdog_softc *sc = device_get_softc(dev); + + sc->dev = dev; + sc->armed = 0; + EVENTHANDLER_REGISTER(watchdog_list, iopwdog_watchdog_fn, sc, 0); + return (0); +} + +static device_method_t iopwdog_methods[] = { + DEVMETHOD(device_probe, iopwdog_probe), + DEVMETHOD(device_attach, iopwdog_attach), + {0, 0}, +}; + +static driver_t iopwdog_driver = { + "iopwdog", + iopwdog_methods, + sizeof(struct iopwdog_softc), +}; +static devclass_t iopwdog_devclass; + +DRIVER_MODULE(iopwdog, iq, iopwdog_driver, iopwdog_devclass, 0, 0); diff --git a/sys/arm/xscale/i8134x/i80321reg.h b/sys/arm/xscale/i8134x/i80321reg.h new file mode 100644 index 000000000000..b6dd4fea14da --- /dev/null +++ b/sys/arm/xscale/i8134x/i80321reg.h @@ -0,0 +1,455 @@ +/* $NetBSD: i80321reg.h,v 1.14 2003/12/19 10:08:11 gavan Exp $ */ + +/*- + * Copyright (c) 2002 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. + * + * $FreeBSD$ + * + */ + +#ifndef _ARM_XSCALE_I80321REG_H_ +#define _ARM_XSCALE_I80321REG_H_ + +/* + * Register definitions for the Intel 80321 (``Verde'') I/O processor, + * based on the XScale core. + */ + +/* + * Base i80321 memory map: + * + * 0x0000.0000 - 0x7fff.ffff ATU Outbound Direct Addressing Window + * 0x8000.0000 - 0x9001.ffff ATU Outbound Translation Windows + * 0x9002.0000 - 0xffff.dfff External Memory + * 0xffff.e000 - 0xffff.e8ff Peripheral Memory Mapped Registers + * 0xffff.e900 - 0xffff.ffff Reserved + */ + +#define VERDE_OUT_DIRECT_WIN_BASE 0x00000000UL +#define VERDE_OUT_DIRECT_WIN_SIZE 0x80000000UL + +#define VERDE_OUT_XLATE_MEM_WIN_SIZE 0x04000000UL +#define VERDE_OUT_XLATE_IO_WIN_SIZE 0x00010000UL + +#define VERDE_OUT_XLATE_MEM_WIN0_BASE 0x80000000UL +#define VERDE_OUT_XLATE_MEM_WIN1_BASE 0x84000000UL + +#define VERDE_OUT_XLATE_IO_WIN0_BASE 0x90000000UL + +#define VERDE_EXTMEM_BASE 0x90020000UL + +#define VERDE_PMMR_BASE 0xffffe000UL +#define VERDE_PMMR_SIZE 0x00001700UL + +/* + * Peripheral Memory Mapped Registers. Defined as offsets + * from the VERDE_PMMR_BASE. + */ +#define VERDE_ATU_BASE 0x0100 +#define VERDE_ATU_SIZE 0x0100 + +#define VERDE_MU_BASE 0x0300 +#define VERDE_MU_SIZE 0x0100 + +#define VERDE_DMA_BASE 0x0400 +#define VERDE_DMA_BASE0 (VERDE_DMA_BASE + 0x00) +#define VERDE_DMA_BASE1 (VERDE_DMA_BASE + 0x40) +#define VERDE_DMA_SIZE 0x0100 +#define VERDE_DMA_CHSIZE 0x0040 + +#define VERDE_MCU_BASE 0x0500 +#define VERDE_MCU_SIZE 0x0100 + +#define VERDE_PBIU_BASE 0x0680 +#define VERDE_PBIU_SIZE 0x0080 + +#define VERDE_I2C_BASE 0x1680 +#define VERDE_I2C_BASE0 (VERDE_I2C_BASE + 0x00) +#define VERDE_I2C_BASE1 (VERDE_I2C_BASE + 0x20) +#define VERDE_I2C_SIZE 0x0080 +#define VERDE_I2C_CHSIZE 0x0020 + +/* + * Address Translation Unit + */ + /* 0x00 - 0x38 -- PCI configuration space header */ +#define ATU_IALR0 0x40 /* Inbound ATU Limit 0 */ +#define ATU_IATVR0 0x44 /* Inbound ATU Xlate Value 0 */ +#define ATU_ERLR 0x48 /* Expansion ROM Limit */ +#define ATU_ERTVR 0x4c /* Expansion ROM Xlate Value */ +#define ATU_IALR1 0x50 /* Inbound ATU Limit 1 */ +#define ATU_IALR2 0x54 /* Inbound ATU Limit 2 */ +#define ATU_IATVR2 0x58 /* Inbound ATU Xlate Value 2 */ +#define ATU_OIOWTVR 0x5c /* Outbound I/O Window Xlate Value */ +#define ATU_OMWTVR0 0x60 /* Outbound Mem Window Xlate Value 0 */ +#define ATU_OUMWTVR0 0x64 /* Outbound Mem Window Xlate Value 0 Upper */ +#define ATU_OMWTVR1 0x68 /* Outbound Mem Window Xlate Value 1 */ +#define ATU_OUMWTVR1 0x6c /* Outbound Mem Window Xlate Value 1 Upper */ +#define ATU_OUDWTVR 0x78 /* Outbound Mem Direct Xlate Value Upper */ +#define ATU_ATUCR 0x80 /* ATU Configuration */ +#define ATU_PCSR 0x84 /* PCI Configuration and Status */ +#define ATU_ATUISR 0x88 /* ATU Interrupt Status */ +#define ATU_ATUIMR 0x8c /* ATU Interrupt Mask */ +#define ATU_IABAR3 0x90 /* Inbound ATU Base Address 3 */ +#define ATU_IAUBAR3 0x94 /* Inbound ATU Base Address 3 Upper */ +#define ATU_IALR3 0x98 /* Inbound ATU Limit 3 */ +#define ATU_IATVR3 0x9c /* Inbound ATU Xlate Value 3 */ +#define ATU_OCCAR 0xa4 /* Outbound Configuration Cycle Address */ +#define ATU_OCCDR 0xac /* Outbound Configuration Cycle Data */ +#define ATU_MSI_PORT 0xb4 /* MSI port */ +#define ATU_PDSCR 0xbc /* PCI Bus Drive Strength Control */ +#define ATU_PCI_X_CAP_ID 0xe0 /* (1) */ +#define ATU_PCI_X_NEXT 0xe1 /* (1) */ +#define ATU_PCIXCMD 0xe2 /* PCI-X Command Register (2) */ +#define ATU_PCIXSR 0xe4 /* PCI-X Status Register */ + +#define ATUCR_DRC_ALIAS (1U << 19) +#define ATUCR_DAU2GXEN (1U << 18) +#define ATUCR_P_SERR_MA (1U << 16) +#define ATUCR_DTS (1U << 15) +#define ATUCR_P_SERR_DIE (1U << 9) +#define ATUCR_DAE (1U << 8) +#define ATUCR_BIST_IE (1U << 3) +#define ATUCR_OUT_EN (1U << 1) + +#define PCSR_DAAAPE (1U << 18) +#define PCSR_PCI_X_CAP (3U << 16) +#define PCSR_PCI_X_CAP_BORING (0 << 16) +#define PCSR_PCI_X_CAP_66 (1U << 16) +#define PCSR_PCI_X_CAP_100 (2U << 16) +#define PCSR_PCI_X_CAP_133 (3U << 16) +#define PCSR_OTQB (1U << 15) +#define PCSR_IRTQB (1U << 14) +#define PCSR_DTV (1U << 12) +#define PCSR_BUS66 (1U << 10) +#define PCSR_BUS64 (1U << 8) +#define PCSR_RIB (1U << 5) +#define PCSR_RPB (1U << 4) +#define PCSR_CCR (1U << 2) +#define PCSR_CPR (1U << 1) + +#define ATUISR_IMW1BU (1U << 14) +#define ATUISR_ISCEM (1U << 13) +#define ATUISR_RSCEM (1U << 12) +#define ATUISR_PST (1U << 11) +#define ATUISR_P_SERR_ASRT (1U << 10) +#define ATUISR_DPE (1U << 9) +#define ATUISR_BIST (1U << 8) +#define ATUISR_IBMA (1U << 7) +#define ATUISR_P_SERR_DET (1U << 4) +#define ATUISR_PMA (1U << 3) +#define ATUISR_PTAM (1U << 2) +#define ATUISR_PTAT (1U << 1) +#define ATUISR_PMPE (1U << 0) + +#define ATUIMR_IMW1BU (1U << 11) +#define ATUIMR_ISCEM (1U << 10) +#define ATUIMR_RSCEM (1U << 9) +#define ATUIMR_PST (1U << 8) +#define ATUIMR_DPE (1U << 7) +#define ATUIMR_P_SERR_ASRT (1U << 6) +#define ATUIMR_PMA (1U << 5) +#define ATUIMR_PTAM (1U << 4) +#define ATUIMR_PTAT (1U << 3) +#define ATUIMR_PMPE (1U << 2) +#define ATUIMR_IE_SERR_EN (1U << 1) +#define ATUIMR_ECC_TAE (1U << 0) + +#define PCIXCMD_MOST_1 (0 << 4) +#define PCIXCMD_MOST_2 (1 << 4) +#define PCIXCMD_MOST_3 (2 << 4) +#define PCIXCMD_MOST_4 (3 << 4) +#define PCIXCMD_MOST_8 (4 << 4) +#define PCIXCMD_MOST_12 (5 << 4) +#define PCIXCMD_MOST_16 (6 << 4) +#define PCIXCMD_MOST_32 (7 << 4) +#define PCIXCMD_MOST_MASK (7 << 4) +#define PCIXCMD_MMRBC_512 (0 << 2) +#define PCIXCMD_MMRBC_1024 (1 << 2) +#define PCIXCMD_MMRBC_2048 (2 << 2) +#define PCIXCMD_MMRBC_4096 (3 << 2) +#define PCIXCMD_MMRBC_MASK (3 << 2) +#define PCIXCMD_ERO (1U << 1) +#define PCIXCMD_DPERE (1U << 0) + +#define PCIXSR_RSCEM (1U << 29) +#define PCIXSR_DMCRS_MASK (7 << 26) +#define PCIXSR_DMOST_MASK (7 << 23) +#define PCIXSR_COMPLEX (1U << 20) +#define PCIXSR_USC (1U << 19) +#define PCIXSR_SCD (1U << 18) +#define PCIXSR_133_CAP (1U << 17) +#define PCIXSR_32PCI (1U << 16) /* 0 = 32, 1 = 64 */ +#define PCIXSR_BUSNO(x) (((x) & 0xff00) >> 8) +#define PCIXSR_DEVNO(x) (((x) & 0xf8) >> 3) +#define PCIXSR_FUNCNO(x) ((x) & 0x7) + +/* + * Memory Controller Unit + */ +#define MCU_SDIR 0x00 /* DDR SDRAM Init. Register */ +#define MCU_SDCR 0x04 /* DDR SDRAM Control Register */ +#define MCU_SDBR 0x08 /* SDRAM Base Register */ +#define MCU_SBR0 0x0c /* SDRAM Boundary 0 */ +#define MCU_SBR1 0x10 /* SDRAM Boundary 1 */ +#define MCU_ECCR 0x34 /* ECC Control Register */ +#define MCU_ELOG0 0x38 /* ECC Log 0 */ +#define MCU_ELOG1 0x3c /* ECC Log 1 */ +#define MCU_ECAR0 0x40 /* ECC address 0 */ +#define MCU_ECAR1 0x44 /* ECC address 1 */ +#define MCU_ECTST 0x48 /* ECC test register */ +#define MCU_MCISR 0x4c /* MCU Interrupt Status Register */ +#define MCU_RFR 0x50 /* Refresh Frequency Register */ +#define MCU_DBUDSR 0x54 /* Data Bus Pull-up Drive Strength */ +#define MCU_DBDDSR 0x58 /* Data Bus Pull-down Drive Strength */ +#define MCU_CUDSR 0x5c /* Clock Pull-up Drive Strength */ +#define MCU_CDDSR 0x60 /* Clock Pull-down Drive Strength */ +#define MCU_CEUDSR 0x64 /* Clock En Pull-up Drive Strength */ +#define MCU_CEDDSR 0x68 /* Clock En Pull-down Drive Strength */ +#define MCU_CSUDSR 0x6c /* Chip Sel Pull-up Drive Strength */ +#define MCU_CSDDSR 0x70 /* Chip Sel Pull-down Drive Strength */ +#define MCU_REUDSR 0x74 /* Rx En Pull-up Drive Strength */ +#define MCU_REDDSR 0x78 /* Rx En Pull-down Drive Strength */ +#define MCU_ABUDSR 0x7c /* Addr Bus Pull-up Drive Strength */ +#define MCU_ABDDSR 0x80 /* Addr Bus Pull-down Drive Strength */ +#define MCU_DSDR 0x84 /* Data Strobe Delay Register */ +#define MCU_REDR 0x88 /* Rx Enable Delay Register */ + +#define SDCR_DIMMTYPE (1U << 1) /* 0 = unbuf, 1 = reg */ +#define SDCR_BUSWIDTH (1U << 2) /* 0 = 64, 1 = 32 */ + +#define SBRx_TECH (1U << 31) +#define SBRx_BOUND 0x0000003f + +#define ECCR_SBERE (1U << 0) +#define ECCR_MBERE (1U << 1) +#define ECCR_SBECE (1U << 2) +#define ECCR_ECCEN (1U << 3) + +#define ELOGx_SYNDROME 0x000000ff +#define ELOGx_ERRTYPE (1U << 8) /* 1 = multi-bit */ +#define ELOGx_RW (1U << 12) /* 1 = write error */ + /* + * Dev ID Func Requester + * 2 0 XScale core + * 2 1 ATU + * 13 0 DMA channel 0 + * 13 1 DMA channel 1 + * 26 0 ATU + */ +#define ELOGx_REQ_DEV(x) (((x) >> 19) & 0x1f) +#define ELOGx_REQ_FUNC(x) (((x) >> 16) & 0x3) + +#define MCISR_ECC_ERR0 (1U << 0) +#define MCISR_ECC_ERR1 (1U << 1) +#define MCISR_ECC_ERRN (1U << 2) + +/* + * Timers + * + * The i80321 timer registers are available in both memory-mapped + * and coprocessor spaces. Most of the registers are read-only + * if memory-mapped, so we access them via coprocessor space. + * + * TMR0 cp6 c0,1 0xffffe7e0 + * TMR1 cp6 c1,1 0xffffe7e4 + * TCR0 cp6 c2,1 0xffffe7e8 + * TCR1 cp6 c3,1 0xffffe7ec + * TRR0 cp6 c4,1 0xffffe7f0 + * TRR1 cp6 c5,1 0xffffe7f4 + * TISR cp6 c6,1 0xffffe7f8 + * WDTCR cp6 c7,1 0xffffe7fc + */ + +#define TMRx_TC (1U << 0) +#define TMRx_ENABLE (1U << 1) +#define TMRx_RELOAD (1U << 2) +#define TMRx_CSEL_CORE (0 << 4) +#define TMRx_CSEL_CORE_div4 (1 << 4) +#define TMRx_CSEL_CORE_div8 (2 << 4) +#define TMRx_CSEL_CORE_div16 (3 << 4) + +#define TISR_TMR0 (1U << 0) +#define TISR_TMR1 (1U << 1) + +#define WDTCR_ENABLE1 0x1e1e1e1e +#define WDTCR_ENABLE2 0xe1e1e1e1 + +/* + * Interrupt Controller Unit. + * + * INTCTL cp6 c0,0 0xffffe7d0 + * INTSTR cp6 c4,0 0xffffe7d4 + * IINTSRC cp6 c8,0 0xffffe7d8 + * FINTSRC cp6 c9,0 0xffffe7dc + * PIRSR 0xffffe1ec + */ + +#define ICU_PIRSR 0x01ec +#define ICU_GPOE 0x07c4 +#define ICU_GPID 0x07c8 +#define ICU_GPOD 0x07cc + +/* + * NOTE: WE USE THE `bitXX' BITS TO INDICATE PENDING SOFTWARE + * INTERRUPTS. See i80321_icu.c + */ +#define ICU_INT_HPI 31 /* high priority interrupt */ +#define ICU_INT_XINT0 27 /* external interrupts */ +#define ICU_INT_XINT(x) ((x) + ICU_INT_XINT0) +#define ICU_INT_bit26 26 + +/* CPU_XSCALE_80321 */ +#define ICU_INT_SSP 25 /* SSP serial port */ + +#define ICU_INT_MUE 24 /* msg unit error */ + +/* CPU_XSCALE_80321 */ +#define ICU_INT_AAUE 23 /* AAU error */ + +#define ICU_INT_bit22 22 +#define ICU_INT_DMA1E 21 /* DMA Ch 1 error */ +#define ICU_INT_DMA0E 20 /* DMA Ch 0 error */ +#define ICU_INT_MCUE 19 /* memory controller error */ +#define ICU_INT_ATUE 18 /* ATU error */ +#define ICU_INT_BIUE 17 /* bus interface unit error */ +#define ICU_INT_PMU 16 /* XScale PMU */ +#define ICU_INT_PPM 15 /* peripheral PMU */ +#define ICU_INT_BIST 14 /* ATU Start BIST */ +#define ICU_INT_MU 13 /* messaging unit */ +#define ICU_INT_I2C1 12 /* i2c unit 1 */ +#define ICU_INT_I2C0 11 /* i2c unit 0 */ +#define ICU_INT_TMR1 10 /* timer 1 */ +#define ICU_INT_TMR0 9 /* timer 0 */ +#define ICU_INT_CPPM 8 /* core processor PMU */ + +/* CPU_XSCALE_80321 */ +#define ICU_INT_AAU_EOC 7 /* AAU end-of-chain */ +#define ICU_INT_AAU_EOT 6 /* AAU end-of-transfer */ + +#define ICU_INT_bit5 5 +#define ICU_INT_bit4 4 +#define ICU_INT_DMA1_EOC 3 /* DMA1 end-of-chain */ +#define ICU_INT_DMA1_EOT 2 /* DMA1 end-of-transfer */ +#define ICU_INT_DMA0_EOC 1 /* DMA0 end-of-chain */ +#define ICU_INT_DMA0_EOT 0 /* DMA0 end-of-transfer */ + +/* CPU_XSCALE_80321 */ +#define ICU_INT_HWMASK (0xffffffff & \ + ~((1 << ICU_INT_bit26) | \ + (1 << ICU_INT_bit22) | \ + (1 << ICU_INT_bit5) | \ + (1 << ICU_INT_bit4))) + +/* + * Peripheral Bus Interface Unit + */ + +#define PBIU_PBCR 0x00 /* PBIU Control Register */ +#define PBIU_PBBAR0 0x08 /* PBIU Base Address Register 0 */ +#define PBIU_PBLR0 0x0c /* PBIU Limit Register 0 */ +#define PBIU_PBBAR1 0x10 /* PBIU Base Address Register 1 */ +#define PBIU_PBLR1 0x14 /* PBIU Limit Register 1 */ +#define PBIU_PBBAR2 0x18 /* PBIU Base Address Register 2 */ +#define PBIU_PBLR2 0x1c /* PBIU Limit Register 2 */ +#define PBIU_PBBAR3 0x20 /* PBIU Base Address Register 3 */ +#define PBIU_PBLR3 0x24 /* PBIU Limit Register 3 */ +#define PBIU_PBBAR4 0x28 /* PBIU Base Address Register 4 */ +#define PBIU_PBLR4 0x2c /* PBIU Limit Register 4 */ +#define PBIU_PBBAR5 0x30 /* PBIU Base Address Register 5 */ +#define PBIU_PBLR5 0x34 /* PBIU Limit Register 5 */ +#define PBIU_DSCR 0x38 /* PBIU Drive Strength Control Reg. */ +#define PBIU_MBR0 0x40 /* PBIU Memory-less Boot Reg. 0 */ +#define PBIU_MBR1 0x60 /* PBIU Memory-less Boot Reg. 1 */ +#define PBIU_MBR2 0x64 /* PBIU Memory-less Boot Reg. 2 */ + +#define PBIU_PBCR_PBIEN (1 << 0) +#define PBIU_PBCR_PBI100 (1 << 1) +#define PBIU_PBCR_PBI66 (2 << 1) +#define PBIU_PBCR_PBI33 (3 << 1) +#define PBIU_PBCR_PBBEN (1 << 3) + +#define PBIU_PBARx_WIDTH8 (0 << 0) +#define PBIU_PBARx_WIDTH16 (1 << 0) +#define PBIU_PBARx_WIDTH32 (2 << 0) +#define PBIU_PBARx_ADWAIT4 (0 << 2) +#define PBIU_PBARx_ADWAIT8 (1 << 2) +#define PBIU_PBARx_ADWAIT12 (2 << 2) +#define PBIU_PBARx_ADWAIT16 (3 << 2) +#define PBIU_PBARx_ADWAIT20 (4 << 2) +#define PBIU_PBARx_RCWAIT1 (0 << 6) +#define PBIU_PBARx_RCWAIT4 (1 << 6) +#define PBIU_PBARx_RCWAIT8 (2 << 6) +#define PBIU_PBARx_RCWAIT12 (3 << 6) +#define PBIU_PBARx_RCWAIT16 (4 << 6) +#define PBIU_PBARx_RCWAIT20 (5 << 6) +#define PBIU_PBARx_FWE (1 << 9) +#define PBIU_BASE_MASK 0xfffff000U + +#define PBIU_PBLRx_SIZE(x) (~((x) - 1)) + +/* + * Messaging Unit + */ +#define MU_IMR0 0x0010 /* MU Inbound Message Register 0 */ +#define MU_IMR1 0x0014 /* MU Inbound Message Register 1 */ +#define MU_OMR0 0x0018 /* MU Outbound Message Register 0 */ +#define MU_OMR1 0x001c /* MU Outbound Message Register 1 */ +#define MU_IDR 0x0020 /* MU Inbound Doorbell Register */ +#define MU_IISR 0x0024 /* MU Inbound Interrupt Status Reg */ +#define MU_IIMR 0x0028 /* MU Inbound Interrupt Mask Reg */ +#define MU_ODR 0x002c /* MU Outbound Doorbell Register */ +#define MU_OISR 0x0030 /* MU Outbound Interrupt Status Reg */ +#define MU_OIMR 0x0034 /* MU Outbound Interrupt Mask Reg */ +#define MU_MUCR 0x0050 /* MU Configuration Register */ +#define MU_QBAR 0x0054 /* MU Queue Base Address Register */ +#define MU_IFHPR 0x0060 /* MU Inbound Free Head Pointer Reg */ +#define MU_IFTPR 0x0064 /* MU Inbound Free Tail Pointer Reg */ +#define MU_IPHPR 0x0068 /* MU Inbound Post Head Pointer Reg */ +#define MU_IPTPR 0x006c /* MU Inbound Post Tail Pointer Reg */ +#define MU_OFHPR 0x0070 /* MU Outbound Free Head Pointer Reg */ +#define MU_OFTPR 0x0074 /* MU Outbound Free Tail Pointer Reg */ +#define MU_OPHPR 0x0078 /* MU Outbound Post Head Pointer Reg */ +#define MU_OPTPR 0x007c /* MU Outbound Post Tail Pointer Reg */ +#define MU_IAR 0x0080 /* MU Index Address Register */ + +#define MU_IIMR_IRI (1 << 6) /* Index Register Interrupt */ +#define MU_IIMR_OFQFI (1 << 5) /* Outbound Free Queue Full Int. */ +#define MU_IIMR_IPQI (1 << 4) /* Inbound Post Queue Interrupt */ +#define MU_IIMR_EDI (1 << 3) /* Error Doorbell Interrupt */ +#define MU_IIMR_IDI (1 << 2) /* Inbound Doorbell Interrupt */ +#define MU_IIMR_IM1I (1 << 1) /* Inbound Message 1 Interrupt */ +#define MU_IIMR_IM0I (1 << 0) /* Inbound Message 0 Interrupt */ + +#endif /* _ARM_XSCALE_I80321REG_H_ */ diff --git a/sys/arm/xscale/i8134x/i80321var.h b/sys/arm/xscale/i8134x/i80321var.h new file mode 100644 index 000000000000..0fead2577a2e --- /dev/null +++ b/sys/arm/xscale/i8134x/i80321var.h @@ -0,0 +1,137 @@ +/* $NetBSD: i80321var.h,v 1.8 2003/10/06 16:06:06 thorpej Exp $ */ + +/*- + * Copyright (c) 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. + * + * $FreeBSD$ + * + */ + +#ifndef _ARM_XSCALE_I80321VAR_H_ +#define _ARM_XSCALE_I80321VAR_H_ + +#include +#include +#include + +extern struct bus_space i80321_bs_tag; + +struct i80321_softc { + device_t dev; + bus_space_tag_t sc_st; + bus_space_handle_t sc_sh; + /* Handles for the various subregions. */ + bus_space_handle_t sc_atu_sh; + bus_space_handle_t sc_mcu_sh; + int sc_is_host; + + /* + * We expect the board-specific front-end to have already mapped + * the PCI I/O space .. it is only 64K, and I/O mappings tend to + * be smaller than a page size, so it's generally more efficient + * to map them all into virtual space in one fell swoop. + */ + vm_offset_t sc_iow_vaddr; /* I/O window vaddr */ + + /* + * Variables that define the Inbound windows. The base address of + * 0-2 are configured by a host via BARs. The xlate variable + * defines the start of the local address space that it maps to. + * The size variable defines the byte size. + * + * The first 3 windows are for incoming PCI memory read/write + * cycles from a host. The 4th window, not configured by the + * host (as it outside the normal BAR range) is the inbound + * window for PCI devices controlled by the i80321. + */ + struct { + uint32_t iwin_base_hi; + uint32_t iwin_base_lo; + uint32_t iwin_xlate; + uint32_t iwin_size; + } sc_iwin[4]; + + /* + * Variables that define the Outbound windows. + */ + struct { + uint32_t owin_xlate_lo; + uint32_t owin_xlate_hi; + } sc_owin[2]; + + /* + * This is the PCI address that the Outbound I/O + * window maps to. + */ + uint32_t sc_ioout_xlate; + + /* Bus space, DMA, and PCI tags for the PCI bus (private devices). */ + struct bus_space sc_pci_iot; + struct bus_space sc_pci_memt; + + /* GPIO state */ + uint8_t sc_gpio_dir; /* GPIO pin direction (1 == output) */ + uint8_t sc_gpio_val; /* GPIO output pin value */ + struct rman sc_irq_rman; + +}; + + +struct i80321_pci_softc { + device_t sc_dev; + bus_space_tag_t sc_st; + bus_space_handle_t sc_atu_sh; + bus_space_tag_t sc_pciio; + bus_space_tag_t sc_pcimem; + int sc_busno; + struct rman sc_mem_rman; + struct rman sc_io_rman; + struct rman sc_irq_rman; + uint32_t sc_mem; + uint32_t sc_io; +}; + +void i80321_sdram_bounds(bus_space_tag_t, bus_space_handle_t, + vm_paddr_t *, vm_size_t *); + +void i80321_attach(struct i80321_softc *); +void i80321_calibrate_delay(void); + +void i80321_bs_init(bus_space_tag_t, void *); +void i80321_io_bs_init(bus_space_tag_t, void *); +void i80321_mem_bs_init(bus_space_tag_t, void *); +extern int machdep_pci_route_interrupt(device_t pcib, device_t dev, int pin); + + +#endif /* _ARM_XSCALE_I80321VAR_H_ */ diff --git a/sys/arm/xscale/i8134x/i81342.c b/sys/arm/xscale/i8134x/i81342.c new file mode 100644 index 000000000000..ace6004cf9c0 --- /dev/null +++ b/sys/arm/xscale/i8134x/i81342.c @@ -0,0 +1,468 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2006 Olivier Houchard + * 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 ``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 + * 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 + +#define _ARM32_BUS_DMA_PRIVATE +#include +#include +#include + +#include +#include + +#define WDTCR_ENABLE1 0x1e1e1e1e +#define WDTCR_ENABLE2 0xe1e1e1e1 + +static volatile int intr_enabled0; +static volatile int intr_enabled1; +static volatile int intr_enabled2; +static volatile int intr_enabled3; + +struct bus_space i81342_bs_tag; + +/* Read the interrupt pending register */ + +static __inline +uint32_t intpnd0_read(void) +{ + uint32_t ret; + + __asm __volatile("mrc p6, 0, %0, c0, c3, 0" + : "=r" (ret)); + return (ret); +} + +static __inline +uint32_t intpnd1_read(void) +{ + uint32_t ret; + + __asm __volatile("mrc p6, 0, %0, c1, c3, 0" + : "=r" (ret)); + return (ret); +} + +static __inline +uint32_t intpnd2_read(void) +{ + uint32_t ret; + + __asm __volatile("mrc p6, 0, %0, c2, c3, 0" + : "=r" (ret)); + return (ret); +} + +static __inline +uint32_t intpnd3_read(void) +{ + uint32_t ret; + + __asm __volatile("mrc p6, 0, %0, c3, c3, 0" + : "=r" (ret)); + return (ret); +} + +/* Read the interrupt control register */ +/* 0 masked, 1 unmasked */ +static __inline +uint32_t intctl0_read(void) +{ + uint32_t ret; + + __asm __volatile("mrc p6, 0, %0, c0, c4, 0" + : "=r" (ret)); + return (ret); +} + +static __inline +uint32_t intctl1_read(void) +{ + uint32_t ret; + + __asm __volatile("mrc p6, 0, %0, c1, c4, 0" + : "=r" (ret)); + return (ret); +} + +static __inline +uint32_t intctl2_read(void) +{ + uint32_t ret; + + __asm __volatile("mrc p6, 0, %0, c2, c4, 0" + : "=r" (ret)); + return (ret); +} + +static __inline +uint32_t intctl3_read(void) +{ + uint32_t ret; + + __asm __volatile("mrc p6, 0, %0, c3, c4, 0" + : "=r" (ret)); + return (ret); +} + +/* Write the interrupt control register */ + +static __inline +void intctl0_write(uint32_t val) +{ + + __asm __volatile("mcr p6, 0, %0, c0, c4, 0" + : : "r" (val)); +} + +static __inline +void intctl1_write(uint32_t val) +{ + + __asm __volatile("mcr p6, 0, %0, c1, c4, 0" + : : "r" (val)); +} + +static __inline +void intctl2_write(uint32_t val) +{ + + __asm __volatile("mcr p6, 0, %0, c2, c4, 0" + : : "r" (val)); +} + +static __inline +void intctl3_write(uint32_t val) +{ + + __asm __volatile("mcr p6, 0, %0, c3, c4, 0" + : : "r" (val)); +} + +/* Read the interrupt steering register */ +/* 0 IRQ 1 FIQ */ +static __inline +uint32_t intstr0_read(void) +{ + uint32_t ret; + + __asm __volatile("mrc p6, 0, %0, c0, c5, 0" + : "=r" (ret)); + return (ret); +} + +static __inline +uint32_t intstr1_read(void) +{ + uint32_t ret; + + __asm __volatile("mrc p6, 0, %0, c1, c5, 0" + : "=r" (ret)); + return (ret); +} + +static __inline +uint32_t intstr2_read(void) +{ + uint32_t ret; + + __asm __volatile("mrc p6, 0, %0, c2, c5, 0" + : "=r" (ret)); + return (ret); +} + +static __inline +uint32_t intstr3_read(void) +{ + uint32_t ret; + + __asm __volatile("mrc p6, 0, %0, c3, c5, 0" + : "=r" (ret)); + return (ret); +} + +/* Write the interrupt steering register */ + +static __inline +void intstr0_write(uint32_t val) +{ + + __asm __volatile("mcr p6, 0, %0, c0, c5, 0" + : : "r" (val)); +} + +static __inline +void intstr1_write(uint32_t val) +{ + + __asm __volatile("mcr p6, 0, %0, c1, c5, 0" + : : "r" (val)); +} + +static __inline +void intstr2_write(uint32_t val) +{ + + __asm __volatile("mcr p6, 0, %0, c2, c5, 0" + : : "r" (val)); +} + +static __inline +void intstr3_write(uint32_t val) +{ + + __asm __volatile("mcr p6, 0, %0, c3, c5, 0" + : : "r" (val)); +} + +void +cpu_reset(void) +{ + + disable_interrupts(PSR_I); + /* XXX: Use the watchdog to reset for now */ + __asm __volatile("mcr p6, 0, %0, c8, c9, 0\n" + "mcr p6, 0, %1, c7, c9, 0\n" + "mcr p6, 0, %2, c7, c9, 0\n" + : : "r" (1), "r" (WDTCR_ENABLE1), "r" (WDTCR_ENABLE2)); + while (1); +} + +void +arm_mask_irq(uintptr_t nb) +{ + + if (nb < 32) { + intr_enabled0 &= ~(1 << nb); + intctl0_write(intr_enabled0); + } else if (nb < 64) { + intr_enabled1 &= ~(1 << (nb - 32)); + intctl1_write(intr_enabled1); + } else if (nb < 96) { + intr_enabled2 &= ~(1 << (nb - 64)); + intctl2_write(intr_enabled2); + } else { + intr_enabled3 &= ~(1 << (nb - 96)); + intctl3_write(intr_enabled3); + } +} + +void +arm_unmask_irq(uintptr_t nb) +{ + if (nb < 32) { + intr_enabled0 |= (1 << nb); + intctl0_write(intr_enabled0); + } else if (nb < 64) { + intr_enabled1 |= (1 << (nb - 32)); + intctl1_write(intr_enabled1); + } else if (nb < 96) { + intr_enabled2 |= (1 << (nb - 64)); + intctl2_write(intr_enabled2); + } else { + intr_enabled3 |= (1 << (nb - 96)); + intctl3_write(intr_enabled3); + } +} + +int +arm_get_next_irq(int last __unused) +{ + uint32_t val; + val = intpnd0_read() & intr_enabled0; + if (val) + return (ffs(val) - 1); + val = intpnd1_read() & intr_enabled1; + if (val) + return (32 + ffs(val) - 1); + val = intpnd2_read() & intr_enabled2; + if (val) + return (64 + ffs(val) - 1); + val = intpnd3_read() & intr_enabled3; + if (val) + return (96 + ffs(val) - 1); + return (-1); +} + +int +bus_dma_get_range_nb(void) +{ + return (0); +} + +struct arm32_dma_range * +bus_dma_get_range(void) +{ + return (NULL); +} + +static int +i81342_probe(device_t dev) +{ + unsigned int freq; + + freq = *(volatile unsigned int *)(IOP34X_VADDR + IOP34X_PFR); + + switch (freq & IOP34X_FREQ_MASK) { + case IOP34X_FREQ_600: + device_set_desc(dev, "Intel 81342 600MHz"); + break; + case IOP34X_FREQ_667: + device_set_desc(dev, "Intel 81342 667MHz"); + break; + case IOP34X_FREQ_800: + device_set_desc(dev, "Intel 81342 800MHz"); + break; + case IOP34X_FREQ_833: + device_set_desc(dev, "Intel 81342 833MHz"); + break; + case IOP34X_FREQ_1000: + device_set_desc(dev, "Intel 81342 1000MHz"); + break; + case IOP34X_FREQ_1200: + device_set_desc(dev, "Intel 81342 1200MHz"); + break; + default: + device_set_desc(dev, "Intel 81342 unknown frequency"); + break; + } + return (0); +} + +static void +i81342_identify(driver_t *driver, device_t parent) +{ + + BUS_ADD_CHILD(parent, 0, "iq", 0); +} + +static int +i81342_attach(device_t dev) +{ + struct i81342_softc *sc = device_get_softc(dev); + uint32_t esstrsr; + + i81342_bs_init(&i81342_bs_tag, sc); + sc->sc_st = &i81342_bs_tag; + sc->sc_sh = IOP34X_VADDR; + esstrsr = bus_space_read_4(sc->sc_st, sc->sc_sh, IOP34X_ESSTSR0); + sc->sc_atux_sh = IOP34X_ATUX_ADDR(esstrsr) - IOP34X_HWADDR + + IOP34X_VADDR; + sc->sc_atue_sh = IOP34X_ATUE_ADDR(esstrsr) - IOP34X_HWADDR + + IOP34X_VADDR; + /* Disable all interrupts. */ + intctl0_write(0); + intctl1_write(0); + intctl2_write(0); + intctl3_write(0); + /* Defaults to IRQ */ + intstr0_write(0); + intstr1_write(0); + intstr2_write(0); + intstr3_write(0); + sc->sc_irq_rman.rm_type = RMAN_ARRAY; + sc->sc_irq_rman.rm_descr = "i81342 IRQs"; + if (rman_init(&sc->sc_irq_rman) != 0 || + rman_manage_region(&sc->sc_irq_rman, 0, 127) != 0) + panic("i81342_attach: failed to set up IRQ rman"); + + device_add_child(dev, "obio", 0); + device_add_child(dev, "itimer", 0); + device_add_child(dev, "iopwdog", 0); + device_add_child(dev, "pcib", 0); + device_add_child(dev, "pcib", 1); + device_add_child(dev, "iqseg", 0); + bus_generic_probe(dev); + bus_generic_attach(dev); + return (0); +} + +static struct resource * +i81342_alloc_resource(device_t dev, device_t child, int type, int *rid, + rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) +{ + struct i81342_softc *sc = device_get_softc(dev); + struct resource *rv; + + if (type == SYS_RES_IRQ) { + rv = rman_reserve_resource(&sc->sc_irq_rman, + start, end, count, flags, child); + if (rv != NULL) + rman_set_rid(rv, *rid); + return (rv); + } + + return (NULL); +} + +static int +i81342_setup_intr(device_t dev, device_t child, struct resource *ires, + int flags, driver_filter_t *filt, driver_intr_t *intr, void *arg, + void **cookiep) +{ + int error; + + error = BUS_SETUP_INTR(device_get_parent(dev), child, ires, flags, + filt, intr, arg, cookiep); + if (error) + return (error); + return (0); +} + +static int +i81342_teardown_intr(device_t dev, device_t child, struct resource *res, + void *cookie) +{ + return (BUS_TEARDOWN_INTR(device_get_parent(dev), child, res, cookie)); +} + +static device_method_t i81342_methods[] = { + DEVMETHOD(device_probe, i81342_probe), + DEVMETHOD(device_attach, i81342_attach), + DEVMETHOD(device_identify, i81342_identify), + DEVMETHOD(bus_alloc_resource, i81342_alloc_resource), + DEVMETHOD(bus_setup_intr, i81342_setup_intr), + DEVMETHOD(bus_teardown_intr, i81342_teardown_intr), + {0, 0}, +}; + +static driver_t i81342_driver = { + "iq", + i81342_methods, + sizeof(struct i81342_softc), +}; +static devclass_t i81342_devclass; + +DRIVER_MODULE(iq, nexus, i81342_driver, i81342_devclass, 0, 0); diff --git a/sys/arm/xscale/i8134x/i81342_mcu.c b/sys/arm/xscale/i8134x/i81342_mcu.c new file mode 100644 index 000000000000..a144774233ff --- /dev/null +++ b/sys/arm/xscale/i8134x/i81342_mcu.c @@ -0,0 +1,58 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2006 Olivier Houchard + * 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 ``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 + * 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 + +void +i81342_sdram_bounds(bus_space_tag_t bt, bus_space_handle_t bh, + vm_paddr_t *start, vm_size_t *size) +{ + uint32_t reg; + int bank_nb; + + reg = bus_space_read_4(bt, bh, SMC_SDBR); + *start = (reg & SMC_SDBR_BASEADDR_MASK); + reg = bus_space_read_4(bt, bh, SMC_SBSR); + if (reg & SMC_SBSR_BANK_NB) + bank_nb = 1; + else + bank_nb = 2; + + *size = (reg & SMC_SBSR_BANK_SZ_MASK) * bank_nb; +} diff --git a/sys/arm/xscale/i8134x/i81342_pci.c b/sys/arm/xscale/i8134x/i81342_pci.c new file mode 100644 index 000000000000..fc348ef1da67 --- /dev/null +++ b/sys/arm/xscale/i8134x/i81342_pci.c @@ -0,0 +1,547 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2006 Olivier Houchard + * 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 ``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 + * 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 "pcib_if.h" + +#include + +static pcib_read_config_t i81342_pci_read_config; +static pcib_write_config_t i81342_pci_write_config; + +static int +i81342_pci_probe(device_t dev) +{ + struct i81342_pci_softc *sc; + + sc = device_get_softc(dev); + if (device_get_unit(dev) == 0) { + device_set_desc(dev, "i81342 PCI-X bus"); + sc->sc_is_atux = 1; + } else { + device_set_desc(dev, "i81342 PCIe bus"); + sc->sc_is_atux = 0; + } + return (0); +} + +#define PCI_MAPREG_MEM_PREFETCHABLE_MASK 0x00000008 +#define PCI_MAPREG_MEM_TYPE_64BIT 0x00000004 + +static int +i81342_pci_attach(device_t dev) +{ + struct i81342_softc *parent_sc; + struct i81342_pci_softc *sc; + uint32_t memsize, memstart; + uint32_t reg; + int func; + uint32_t busno; + + sc = device_get_softc(dev); + parent_sc = device_get_softc(device_get_parent(dev)); + sc->sc_atu_sh = sc->sc_is_atux ? parent_sc->sc_atux_sh : + parent_sc->sc_atue_sh; + sc->sc_st = parent_sc->sc_st; + if (bus_space_read_4(sc->sc_st, parent_sc->sc_sh, IOP34X_ESSTSR0) + & IOP34X_INT_SEL_PCIX) { + if (sc->sc_is_atux) + func = 5; + else + func = 0; + } else { + if (sc->sc_is_atux) + func = 0; + else + func = 5; + } + i81342_io_bs_init(&sc->sc_pciio, sc); + i81342_mem_bs_init(&sc->sc_pcimem, sc); + i81342_sdram_bounds(sc->sc_st, IOP34X_VADDR, &memstart, &memsize); + if (sc->sc_is_atux) { + reg = bus_space_read_4(sc->sc_st, sc->sc_atu_sh, ATU_PCSR); + if (reg & ATUX_P_RSTOUT) { + bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_PCSR, + reg &~ ATUX_P_RSTOUT); + DELAY(200); + } + } + /* Setup the Inbound windows. */ + bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IABAR0, 0); + bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IAUBAR0, 0); + bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IALR0, 0); + + /* Set the mapping Physical address <=> PCI address */ + bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IABAR1, + memstart | PCI_MAPREG_MEM_PREFETCHABLE_MASK | + PCI_MAPREG_MEM_TYPE_64BIT); + bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IAUBAR1, 0); + bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IALR1, + rounddown2(~(0xfff), memsize)); + bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IATVR1, memstart); + bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IAUTVR1, 0); + + bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IABAR2, 0); + bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IAUBAR2, 0); + bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IALR2, 0); + + /* Setup the Outbound IO Bar */ + if (sc->sc_is_atux) + bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_OIOBAR, + (IOP34X_PCIX_OIOBAR >> 4) | func); + else + bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_OIOBAR, + (IOP34X_PCIE_OIOBAR >> 4) | func); + + /* Setup the Outbound windows */ + bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_OUMBAR0, 0); + if (sc->sc_is_atux) + bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_OUMBAR1, + (IOP34X_PCIX_OMBAR >> 32) | (func << ATU_OUMBAR_FUNC) | + ATU_OUMBAR_EN); + else + bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_OUMBAR1, + (IOP34X_PCIE_OMBAR >> 32) | (func << ATU_OUMBAR_FUNC) | + ATU_OUMBAR_EN); + bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_OUMWTVR1, 0); + bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_OUMBAR2, 0); + bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_OUMBAR3, 0); + + /* Enable the outbound windows. */ + reg = bus_space_read_4(sc->sc_st, sc->sc_atu_sh, ATU_CR); + bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_CR, + reg | ATU_CR_OUT_EN); + + bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_ISR, + bus_space_read_4(sc->sc_st, sc->sc_atu_sh, ATU_ISR) & ATUX_ISR_ERRMSK); + /* + * Enable bus mastering, memory access, SERR, and parity + * checking on the ATU. + */ + if (sc->sc_is_atux) { + busno = bus_space_read_4(sc->sc_st, sc->sc_atu_sh, ATU_PCIXSR); + busno = PCIXSR_BUSNO(busno); + } else { + busno = bus_space_read_4(sc->sc_st, sc->sc_atu_sh, ATU_PCSR); + busno = PCIE_BUSNO(busno); + } + reg = bus_space_read_2(sc->sc_st, sc->sc_atu_sh, ATU_CMD); + reg |= PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN | PCIM_CMD_PERRESPEN | + PCIM_CMD_SERRESPEN; + bus_space_write_2(sc->sc_st, sc->sc_atu_sh, ATU_CMD, reg); + sc->sc_busno = busno; + /* Initialize memory and i/o rmans. */ + sc->sc_io_rman.rm_type = RMAN_ARRAY; + sc->sc_io_rman.rm_descr = "I81342 PCI I/O Ports"; + if (rman_init(&sc->sc_io_rman) != 0 || + rman_manage_region(&sc->sc_io_rman, + sc->sc_is_atux ? IOP34X_PCIX_OIOBAR_VADDR : + IOP34X_PCIE_OIOBAR_VADDR, + (sc->sc_is_atux ? IOP34X_PCIX_OIOBAR_VADDR : + IOP34X_PCIE_OIOBAR_VADDR) + IOP34X_OIOBAR_SIZE) != 0) { + panic("i81342_pci_probe: failed to set up I/O rman"); + } + sc->sc_mem_rman.rm_type = RMAN_ARRAY; + sc->sc_mem_rman.rm_descr = "I81342 PCI Memory"; + if (rman_init(&sc->sc_mem_rman) != 0 || + rman_manage_region(&sc->sc_mem_rman, + 0, 0xffffffff) != 0) { + panic("i81342_pci_attach: failed to set up memory rman"); + } + sc->sc_irq_rman.rm_type = RMAN_ARRAY; + sc->sc_irq_rman.rm_descr = "i81342 PCI IRQs"; + if (sc->sc_is_atux) { + if (rman_init(&sc->sc_irq_rman) != 0 || + rman_manage_region(&sc->sc_irq_rman, ICU_INT_XINT0, + ICU_INT_XINT3) != 0) + panic("i83142_pci_attach: failed to set up IRQ rman"); + } else { + if (rman_init(&sc->sc_irq_rman) != 0 || + rman_manage_region(&sc->sc_irq_rman, ICU_INT_ATUE_MA, + ICU_INT_ATUE_MD) != 0) + panic("i81342_pci_attach: failed to set up IRQ rman"); + + } + bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_ISR, + bus_space_read_4(sc->sc_st, sc->sc_atu_sh, ATU_ISR) & ATUX_ISR_ERRMSK); + device_add_child(dev, "pci", -1); + return (bus_generic_attach(dev)); +} + +static int +i81342_pci_maxslots(device_t dev) +{ + + return (PCI_SLOTMAX); +} + +static void +i81342_pci_conf_setup(struct i81342_pci_softc *sc, int bus, int slot, int func, + int reg, uint32_t *addr) +{ + uint32_t busno; + + if (sc->sc_is_atux) { + busno = bus_space_read_4(sc->sc_st, sc->sc_atu_sh, ATU_PCIXSR); + busno = PCIXSR_BUSNO(busno); + } else { + busno = bus_space_read_4(sc->sc_st, sc->sc_atu_sh, ATU_PCSR); + busno = PCIE_BUSNO(busno); + } + bus &= 0xff; + slot &= 0x1f; + func &= 0x7; + if (sc->sc_is_atux) { + if (busno == bus) + *addr = (1 << (slot + 16)) | (slot << 11) | + (func << 8) | reg; + else + *addr = (bus << 16) | (slot << 11) | (func << 11) | + reg | 1; + } else { + *addr = (bus << 24) | (slot << 19) | (func << 16) | reg; + if (bus != busno) + *addr |= 1; + } +} + +static u_int32_t +i81342_pci_read_config(device_t dev, u_int bus, u_int slot, u_int func, + u_int reg, int bytes) +{ + struct i81342_pci_softc *sc = device_get_softc(dev); + uint32_t addr; + uint32_t ret = 0; + uint32_t isr; + int err = 0; + vm_offset_t va; + + i81342_pci_conf_setup(sc, bus, slot, func, reg & ~3, &addr); + bus_space_write_4(sc->sc_st, sc->sc_atu_sh, sc->sc_is_atux ? + ATUX_OCCAR : ATUE_OCCAR, addr); + if (sc->sc_is_atux) + va = sc->sc_atu_sh + ATUX_OCCDR; + else + va = sc->sc_atu_sh + ATUE_OCCDR; + switch (bytes) { + case 1: + err = badaddr_read((void*)(va + (reg & 3)), 1, &ret); + break; + case 2: + err = badaddr_read((void*)(va + (reg & 3)), 2, &ret); + break; + case 4: + err = badaddr_read((void *)(va) , 4, &ret); + break; + default: + printf("i81342_read_config: invalid size %d\n", bytes); + ret = -1; + } + if (err) { + isr = bus_space_read_4(sc->sc_st, sc->sc_atu_sh, ATU_ISR); + if (sc->sc_is_atux) + isr &= ATUX_ISR_ERRMSK; + else + isr &= ATUE_ISR_ERRMSK; + bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_ISR, isr); + ret = -1; + } + + return (ret); +} + +static void +i81342_pci_write_config(device_t dev, u_int bus, u_int slot, u_int func, + u_int reg, u_int32_t data, int bytes) +{ + struct i81342_pci_softc *sc = device_get_softc(dev); + uint32_t addr; + vm_offset_t va; + + i81342_pci_conf_setup(sc, bus, slot, func, reg & ~3, &addr); + bus_space_write_4(sc->sc_st, sc->sc_atu_sh, sc->sc_is_atux ? + ATUX_OCCAR : ATUE_OCCAR, addr); + va = sc->sc_is_atux ? ATUX_OCCDR : ATUE_OCCDR; + switch (bytes) { + case 1: + bus_space_write_1(sc->sc_st, sc->sc_atu_sh, va + (reg & 3) + , data); + break; + case 2: + bus_space_write_2(sc->sc_st, sc->sc_atu_sh, va + (reg & 3) + , data); + break; + case 4: + bus_space_write_4(sc->sc_st, sc->sc_atu_sh, va, data); + break; + default: + printf("i81342_pci_write_config: Invalid size : %d\n", bytes); + } + + +} + +static struct resource * +i81342_pci_alloc_resource(device_t bus, device_t child, int type, int *rid, + rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) +{ + struct i81342_pci_softc *sc = device_get_softc(bus); + struct resource *rv; + struct rman *rm; + bus_space_tag_t bt = NULL; + bus_space_handle_t bh = 0; + + switch (type) { + case SYS_RES_IRQ: + rm = &sc->sc_irq_rman; + break; + case SYS_RES_MEMORY: + rm = &sc->sc_mem_rman; + bt = &sc->sc_pcimem; + bh = 0; + break; + case SYS_RES_IOPORT: + rm = &sc->sc_io_rman; + bt = &sc->sc_pciio; + bh = sc->sc_is_atux ? IOP34X_PCIX_OIOBAR_VADDR : + IOP34X_PCIE_OIOBAR_VADDR; + start += bh; + end += bh; + break; + default: + return (NULL); + } + + rv = rman_reserve_resource(rm, start, end, count, flags, child); + if (rv == NULL) + return (NULL); + rman_set_rid(rv, *rid); + if (type != SYS_RES_IRQ) { + if (type == SYS_RES_MEMORY) + bh += (rman_get_start(rv)); + rman_set_bustag(rv, bt); + rman_set_bushandle(rv, bh); + if (flags & RF_ACTIVE) { + if (bus_activate_resource(child, type, *rid, rv)) { + rman_release_resource(rv); + return (NULL); + } + } + } + return (rv); + + + return (NULL); +} + +static int +i81342_pci_activate_resource(device_t bus, device_t child, int type, int rid, + struct resource *r) +{ + bus_space_handle_t p; + int error; + + if (type == SYS_RES_MEMORY) { + 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); + + } + return (rman_activate_resource(r)); +} + +static int +i81342_pci_setup_intr(device_t dev, device_t child, struct resource *ires, + int flags, driver_filter_t *filt, driver_intr_t *intr, void *arg, + void **cookiep) +{ + + return (BUS_SETUP_INTR(device_get_parent(dev), child, ires, flags, + filt, intr, arg, cookiep)); +} + + + +static int +i81342_pci_teardown_intr(device_t dev, device_t child, struct resource *res, + void *cookie) +{ + return (BUS_TEARDOWN_INTR(device_get_parent(dev), child, res, cookie)); +} + +static int +i81342_pci_route_interrupt(device_t pcib, device_t dev, int pin) +{ + struct i81342_pci_softc *sc; + int device; + + device = pci_get_slot(dev); + sc = device_get_softc(pcib); + /* XXX: Is board specific */ + if (sc->sc_is_atux) { + /* PCI-X */ + switch(device) { + case 1: + switch (pin) { + case 1: + return (ICU_INT_XINT1); + case 2: + return (ICU_INT_XINT2); + case 3: + return (ICU_INT_XINT3); + case 4: + return (ICU_INT_XINT0); + default: + break; + } + case 2: + switch (pin) { + case 1: + return (ICU_INT_XINT2); + case 2: + return (ICU_INT_XINT3); + case 3: + return (ICU_INT_XINT2); + case 4: + return (ICU_INT_XINT3); + default: + break; + } + } + + } else { + switch (pin) { + case 1: + return (ICU_INT_ATUE_MA); + case 2: + return (ICU_INT_ATUE_MB); + case 3: + return (ICU_INT_ATUE_MC); + case 4: + return (ICU_INT_ATUE_MD); + default: + break; + } + } + printf("Warning: couldn't map %s IRQ for device %d pin %d\n", + sc->sc_is_atux ? "PCI-X" : "PCIe", device, pin); + return (-1); +} + +static int +i81342_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) +{ + struct i81342_pci_softc *sc = device_get_softc(dev); + switch (which) { + case PCIB_IVAR_DOMAIN: + *result = 0; + return (0); + case PCIB_IVAR_BUS: + *result = sc->sc_busno; + return (0); + + } + return (ENOENT); +} + +static int +i81342_write_ivar(device_t dev, device_t child, int which, uintptr_t result) +{ + struct i81342_pci_softc * sc = device_get_softc(dev); + + switch (which) { + case PCIB_IVAR_DOMAIN: + return (EINVAL); + case PCIB_IVAR_BUS: + sc->sc_busno = result; + return (0); + } + return (ENOENT); +} + +static device_method_t i81342_pci_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, i81342_pci_probe), + DEVMETHOD(device_attach, i81342_pci_attach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + DEVMETHOD(device_suspend, bus_generic_suspend), + DEVMETHOD(device_resume, bus_generic_resume), + + /* Bus interface */ + DEVMETHOD(bus_read_ivar, i81342_read_ivar), + DEVMETHOD(bus_write_ivar, i81342_write_ivar), + DEVMETHOD(bus_alloc_resource, i81342_pci_alloc_resource), + DEVMETHOD(bus_release_resource, bus_generic_release_resource), + DEVMETHOD(bus_activate_resource, i81342_pci_activate_resource), + DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), + DEVMETHOD(bus_setup_intr, i81342_pci_setup_intr), + DEVMETHOD(bus_teardown_intr, i81342_pci_teardown_intr), + + /* pcib interface */ + DEVMETHOD(pcib_maxslots, i81342_pci_maxslots), + DEVMETHOD(pcib_read_config, i81342_pci_read_config), + DEVMETHOD(pcib_write_config, i81342_pci_write_config), + DEVMETHOD(pcib_route_interrupt, i81342_pci_route_interrupt), + DEVMETHOD(pcib_request_feature, pcib_request_feature_allow), + + DEVMETHOD_END +}; + +static driver_t i81342_pci_driver = { + "pcib", + i81342_pci_methods, + sizeof(struct i81342_pci_softc), +}; + +static devclass_t i81342_pci_devclass; + +DRIVER_MODULE(ipci, iq, i81342_pci_driver, i81342_pci_devclass, 0, 0); diff --git a/sys/arm/xscale/i8134x/i81342_space.c b/sys/arm/xscale/i8134x/i81342_space.c new file mode 100644 index 000000000000..ed27675e4a0f --- /dev/null +++ b/sys/arm/xscale/i8134x/i81342_space.c @@ -0,0 +1,234 @@ +/* $NetBSD: i80321_space.c,v 1.6 2003/10/06 15:43:35 thorpej Exp $ */ + +/*- + * SPDX-License-Identifier: BSD-4-Clause + * + * Copyright (c) 2001, 2002 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 i81342 I/O Processor. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include + +/* Prototypes for all the bus_space structure functions */ +bs_protos(i81342); +bs_protos(i81342_io); +bs_protos(i81342_mem); + +void +i81342_bs_init(bus_space_tag_t bs, void *cookie) +{ + + *bs = *arm_base_bs_tag; + bs->bs_privdata = cookie; +} + +void +i81342_io_bs_init(bus_space_tag_t bs, void *cookie) +{ + + *bs = *arm_base_bs_tag; + bs->bs_privdata = cookie; + + bs->bs_map = i81342_io_bs_map; + bs->bs_unmap = i81342_io_bs_unmap; + bs->bs_alloc = i81342_io_bs_alloc; + bs->bs_free = i81342_io_bs_free; + +} + +void +i81342_mem_bs_init(bus_space_tag_t bs, void *cookie) +{ + + *bs = *arm_base_bs_tag; + bs->bs_privdata = cookie; + + bs->bs_map = i81342_mem_bs_map; + bs->bs_unmap = i81342_mem_bs_unmap; + bs->bs_alloc = i81342_mem_bs_alloc; + bs->bs_free = i81342_mem_bs_free; + +} + +/* *** Routines shared by i81342, PCI IO, and PCI MEM. *** */ + +int +i81342_bs_subregion(bus_space_tag_t tag, bus_space_handle_t bsh, bus_size_t offset, + bus_size_t size, bus_space_handle_t *nbshp) +{ + + *nbshp = bsh + offset; + return (0); +} + +void +i81342_bs_barrier(bus_space_tag_t tag, bus_space_handle_t bsh, bus_size_t offset, + bus_size_t len, int flags) +{ + + /* Nothing to do. */ +} + +/* *** Routines for PCI IO. *** */ + +int +i81342_io_bs_map(bus_space_tag_t tag, bus_addr_t bpa, bus_size_t size, int flags, + bus_space_handle_t *bshp) +{ + + *bshp = bpa; + return (0); +} + +void +i81342_io_bs_unmap(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t size) +{ + + /* Nothing to do. */ +} + +int +i81342_io_bs_alloc(bus_space_tag_t tag, bus_addr_t rstart, bus_addr_t rend, + bus_size_t size, bus_size_t alignment, bus_size_t boundary, int flags, + bus_addr_t *bpap, bus_space_handle_t *bshp) +{ + + panic("i81342_io_bs_alloc(): not implemented"); +} + +void +i81342_io_bs_free(bus_space_tag_t tag, bus_space_handle_t bsh, bus_size_t size) +{ + + panic("i81342_io_bs_free(): not implemented"); +} + + +/* *** Routines for PCI MEM. *** */ +extern int badaddr_read(void *, int, void *); +static vm_offset_t allocable = 0xe1000000; +int +i81342_mem_bs_map(bus_space_tag_t tag, bus_addr_t bpa, bus_size_t size, int flags, + bus_space_handle_t *bshp) +{ + struct i81342_pci_softc *sc = (struct i81342_pci_softc *)tag->bs_privdata; + struct i81342_pci_map *tmp; + vm_offset_t addr, endaddr; + vm_paddr_t paddr; + + /* Lookup to see if we already have a mapping at this address. */ + tmp = sc->sc_pci_mappings; + while (tmp) { + if (tmp->paddr <= bpa && tmp->paddr + tmp->size > + bpa + size) { + *bshp = bpa - tmp->paddr + tmp->vaddr; + return (0); + } + tmp = tmp->next; + } + addr = allocable; + endaddr = rounddown2(addr + size, 0x1000000) + 0x1000000; + if (endaddr >= IOP34X_VADDR) + panic("PCI virtual memory exhausted"); + allocable = endaddr; + tmp = malloc(sizeof(*tmp), M_DEVBUF, M_WAITOK); + tmp->next = NULL; + paddr = rounddown2(bpa, 0x100000); + tmp->paddr = paddr; + tmp->vaddr = addr; + tmp->size = 0; + while (addr < endaddr) { + pmap_kenter_supersection(addr, paddr + (sc->sc_is_atux ? + IOP34X_PCIX_OMBAR : IOP34X_PCIE_OMBAR), 0); + addr += 0x1000000; + paddr += 0x1000000; + tmp->size += 0x1000000; + } + tmp->next = sc->sc_pci_mappings; + sc->sc_pci_mappings = tmp; + *bshp = bpa - tmp->paddr + tmp->vaddr; + return (0); +} + +void +i81342_mem_bs_unmap(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t size) +{ +#if 0 + vm_offset_t va, endva; + + va = trunc_page((vm_offset_t)h); + endva = va + round_page(size); + + /* Free the kernel virtual mapping. */ + kva_free(va, endva - va); +#endif +} + +int +i81342_mem_bs_alloc(bus_space_tag_t tag, bus_addr_t rstart, bus_addr_t rend, + bus_size_t size, bus_size_t alignment, bus_size_t boundary, int flags, + bus_addr_t *bpap, bus_space_handle_t *bshp) +{ + + panic("i81342_mem_bs_alloc(): not implemented"); +} + +void +i81342_mem_bs_free(bus_space_tag_t tag, bus_space_handle_t bsh, bus_size_t size) +{ + + panic("i81342_mem_bs_free(): not implemented"); +} diff --git a/sys/arm/xscale/i8134x/i81342reg.h b/sys/arm/xscale/i8134x/i81342reg.h new file mode 100644 index 000000000000..07bec22ef89c --- /dev/null +++ b/sys/arm/xscale/i8134x/i81342reg.h @@ -0,0 +1,350 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2006 Olivier Houchard + * 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 ``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 + * 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. + */ + +/* $FreeBSD$ */ + +#ifndef I83142_REG_H_ +#define I83142_REG_H_ +/* Physical Memory Map */ +/* + * 0x000000000 - 0x07FFFFFFF SDRAM + * 0x090100000 - 0x0901FFFFF ATUe Outbound IO Window + * 0x0F0000000 - 0x0F1FFFFFF Flash + * 0x0F2000000 - 0x0F20FFFFF PCE1 + * 0x0F3000000 - 0x0FFCFFFFF Compact Flash + * 0x0FFD00000 - 0x0FFDFFFFF MMR + * 0x0FFFB0000 - 0x0FFFBFFFF ATU-X Outbound I/O Window + * 0x0FFFD0000 - 0x0FFFDFFFF ATUe Outbound I/O Window + * 0x100000000 - 0x1FFFFFFFF ATU-X outbound Memory Translation Window + * 0x2FF000000 - 0x2FFFFFFFF ATUe Outbound Memory Translation Window + */ + +#define IOP34X_VADDR 0xf0000000 +#define IOP34X_HWADDR 0xffd00000 +#define IOP34X_SIZE 0x100000 + +#define IOP34X_ADMA0_OFFSET 0x00080000 +#define IOP34X_ADMA1_OFFSET 0x00080200 +#define IOP34X_ADMA2_OFFSET 0x00080400 +#define IOP34X_ADMA_SIZE 0x200 + + +/* ADMA Registers */ +#define IOP34X_ADMA_CCR 0x0000 /* Channel Control Register */ +#define IOP34X_ADMA_CSR 0x0004 /* Channel Status Register */ +#define IOP34X_ADMA_DAR 0x0008 /* Descriptor Address Register */ +#define IOP34X_ADMA_IPCR 0x0018 /* Internal Interface Parity Ctrl Reg */ +#define IOP34X_ADMA_NDAR 0x0024 /* Next Descriptor Register */ +#define IOP34X_ADMA_DCR 0x0028 /* Descriptor Control Register */ + +#define IOP34X_ADMA_IE (1 << 0) /* Interrupt enable */ +#define IOP34X_ADMA_TR (1 << 1) /* Transfert Direction */ +/* + * Source Destination + * 00 Host I/O Interface Local Memory + * 01 Local Memory Host I/O Interface + * 10 Internal Bus Local Memory + * 11 Local Memory Internal Bus + */ +#define IOP34X_ADMA_SS (1 << 3) /* Source selection */ +/* 0000: Data Transfer / CRC / Memory Block Fill */ +#define IOP34X_ADMA_ZRBCE (1 << 7) /* Zero Result Buffer Check Enable */ +#define IOP34X_ADMA_MBFE (1 << 8) /* Memory Block Fill Enable */ +#define IOP34X_ADMA_CGE (1 << 9) /* CRC Generation enable */ +#define IOP34X_ADMA_CTD (1 << 10) /* CRC Transfer disable */ +#define IOP34X_ADMA_CSFD (1 << 11) /* CRC Seed fetch disable */ +#define IOP34X_ADMA_SWBE (1 << 12) /* Status write back enable */ +#define IOP34X_ADMA_ESE (1 << 13) /* Endian swap enable */ +#define IOP34X_ADMA_PQUTE (1 << 16) /* P+Q Update Transfer Enable */ +#define IOP34X_ADMA_DXE (1 << 17) /* Dual XOR Enable */ +#define IOP34X_ADMA_PQTE (1 << 18) /* P+Q Transfer Enable */ +#define IOP34X_ADMA_PTD (1 << 19) /* P Transfer Disable */ +#define IOP34X_ADMA_ROE (1 << 30) /* Relaxed Ordering Enable */ +#define IOP34X_ADMA_NSE (1U << 31) /* No Snoop Enable */ + +#define IOP34X_PBBAR0 0x81588 /* PBI Base Address Register 0 */ +#define IOP34X_PBBAR0_ADDRMASK 0xfffff000 +#define IOP34X_PBBAR1 0x81590 +#define IOP34X_PCE1 0xF2000000 +#define IOP34X_PCE1_SIZE 0x00100000 +#define IOP34X_PCE1_VADDR 0xF1000000 +#define IOP34X_ESSTSR0 0x82188 +#define IOP34X_CONTROLLER_ONLY (1 << 14) +#define IOP34X_INT_SEL_PCIX (1 << 15) +#define IOP34X_PFR 0x82180 /* Processor Frequency Register */ +#define IOP34X_FREQ_MASK ((1 << 16) | (1 << 17) | (1 << 18)) +#define IOP34X_FREQ_600 (0) +#define IOP34X_FREQ_667 (1 << 16) +#define IOP34X_FREQ_800 (1 << 17) +#define IOP34X_FREQ_833 ((1 << 17) | (1 << 16)) +#define IOP34X_FREQ_1000 (1 << 18) +#define IOP34X_FREQ_1200 ((1 << 16) | (1 << 18)) + +#define IOP34X_UART0_VADDR IOP34X_VADDR + 0x82300 +#define IOP34X_UART0_HWADDR IOP34X_HWADDR + 0x82300 +#define IOP34X_UART1_VADDR IOP34X_VADDR + 0x82340 +#define IOP34X_UART1_HWADDR IOP34X_HWADDR + 0x82340 +#define IOP34X_PBI_HWADDR 0xffd81580 + +/* SDRAM Memory Controller */ +#define SMC_SDBR 0x8180c /* Base Register */ +#define SMC_SDBR_BASEADDR (1 << 27) +#define SMC_SDBR_BASEADDR_MASK ((1 << 27) | (1 << 28) | (1 << 29) | (1 << 30) \ + | (1U << 31)) +#define SMC_SDUBR 0x81810 /* Upper Base Register */ +#define SMC_SBSR 0x81814 /* SDRAM Bank Size Register */ +#define SMC_SBSR_BANK_NB (1 << 2) /* Number of DDR Banks + 0 => 2 Banks + 1 => 1 Bank + */ +#define SMC_SBSR_BANK_SZ (1 << 27) /* SDRAM Bank Size : + 0x00000 Empty + 0x00001 128MB + 0x00010 256MB + 0x00100 512MB + 0x01000 1GB + */ +#define SMC_SBSR_BANK_SZ_MASK ((1 << 27) | (1 << 28) | (1 << 29) | (1 << 30) \ + | (1U << 31)) + + +/* Two possible addresses for ATUe depending on configuration. */ +#define IOP34X_ATUE_ADDR(esstrsr) ((((esstrsr) & (IOP34X_CONTROLLER_ONLY | \ + IOP34X_INT_SEL_PCIX)) == (IOP34X_CONTROLLER_ONLY | IOP34X_INT_SEL_PCIX)) ? \ + 0xffdc8000 : 0xffdcd000) + +/* Three possible addresses for ATU-X depending on configuration. */ +#define IOP34X_ATUX_ADDR(esstrsr) (!((esstrsr) & IOP34X_CONTROLLER_ONLY) ? \ + 0xffdcc000 : !((esstrsr) & IOP34X_INT_SEL_PCIX) ? 0xffdc8000 : 0xffdcd000) + +#define IOP34X_OIOBAR_SIZE 0x10000 +#define IOP34X_PCIX_OIOBAR 0xfffb0000 +#define IOP34X_PCIX_OIOBAR_VADDR 0xf01b0000 +#define IOP34X_PCIX_OMBAR 0x100000000 +#define IOP34X_PCIE_OIOBAR 0xfffd0000 +#define IOP34X_PCIE_OIOBAR_VADDR 0xf01d0000 +#define IOP34X_PCIE_OMBAR 0x200000000 + +/* ATU Registers */ +/* Common for ATU-X and ATUe */ +#define ATU_VID 0x0000 /* ATU Vendor ID */ +#define ATU_DID 0x0002 /* ATU Device ID */ +#define ATU_CMD 0x0004 /* ATU Command Register */ +#define ATU_SR 0x0006 /* ATU Status Register */ +#define ATU_RID 0x0008 /* ATU Revision ID */ +#define ATU_CCR 0x0009 /* ATU Class Code */ +#define ATU_CLSR 0x000c /* ATU Cacheline Size */ +#define ATU_LT 0x000d /* ATU Latency Timer */ +#define ATU_HTR 0x000e /* ATU Header Type */ +#define ATU_BISTR 0x000f /* ATU BIST Register */ +#define ATU_IABAR0 0x0010 /* Inbound ATU Base Address register 0 */ +#define ATU_IAUBAR0 0x0014 /* Inbound ATU Upper Base Address Register 0 */ +#define ATU_IABAR1 0x0018 /* Inbound ATU Base Address Register 1 */ +#define ATU_IAUBAR1 0x001c /* Inbound ATU Upper Base Address Register 1 */ +#define ATU_IABAR2 0x0020 /* Inbound ATU Base Address Register 2 */ +#define ATU_IAUBAR2 0x0024 /* Inbound ATU Upper Base Address Register 2 */ +#define ATU_VSIR 0x002c /* ATU Subsystem Vendor ID Register */ +#define ATU_SIR 0x002e /* ATU Subsystem ID Register */ +#define ATU_ERBAR 0x0030 /* Expansion ROM Base Address Register */ +#define ATU_CAPPTR 0x0034 /* ATU Capabilities Pointer Register */ +#define ATU_ILR 0x003c /* ATU Interrupt Line Register */ +#define ATU_IPR 0x003d /* ATU Interrupt Pin Register */ +#define ATU_MGNT 0x003e /* ATU Minimum Grand Register */ +#define ATU_MLAT 0x003f /* ATU Maximum Latency Register */ +#define ATU_IALR0 0x0040 /* Inbound ATU Limit Register 0 */ +#define ATU_IATVR0 0x0044 /* Inbound ATU Translate Value Register 0 */ +#define ATU_IAUTVR0 0x0048 /* Inbound ATU Upper Translate Value Register 0*/ +#define ATU_IALR1 0x004c /* Inbound ATU Limit Register 1 */ +#define ATU_IATVR1 0x0050 /* Inbound ATU Translate Value Register 1 */ +#define ATU_IAUTVR1 0x0054 /* Inbound ATU Upper Translate Value Register 1*/ +#define ATU_IALR2 0x0058 /* Inbound ATU Limit Register 2 */ +#define ATU_IATVR2 0x005c /* Inbound ATU Translate Value Register 2 */ +#define ATU_IAUTVR2 0x0060 /* Inbound ATU Upper Translate Value Register 2*/ +#define ATU_ERLR 0x0064 /* Expansion ROM Limit Register */ +#define ATU_ERTVR 0x0068 /* Expansion ROM Translator Value Register */ +#define ATU_ERUTVR 0x006c /* Expansion ROM Upper Translate Value Register*/ +#define ATU_CR 0x0070 /* ATU Configuration Register */ +#define ATU_CR_OUT_EN (1 << 1) +#define ATU_PCSR 0x0074 /* PCI Configuration and Status Register */ +#define PCIE_BUSNO(x) ((x & 0xff000000) >> 24) +#define ATUX_CORE_RST ((1 << 30) | (1U << 31)) /* Core Processor Reset */ +#define ATUX_P_RSTOUT (1 << 21) /* Central Resource PCI Bus Reset */ +#define ATUE_CORE_RST ((1 << 9) | (1 << 8)) /* Core Processor Reset */ +#define ATU_ISR 0x0078 /* ATU Interrupt Status Register */ +#define ATUX_ISR_PIE (1 << 18) /* PCI Interface error */ +#define ATUX_ISR_IBPR (1 << 16) /* Internal Bus Parity Error */ +#define ATUX_ISR_DCE (1 << 14) /* Detected Correctable error */ +#define ATUX_ISR_ISCE (1 << 13) /* Initiated Split Completion Error Msg */ +#define ATUX_ISR_RSCE (1 << 12) /* Received Split Completion Error Msg */ +#define ATUX_ISR_DPE (1 << 9) /* Detected Parity Error */ +#define ATUX_ISR_IBMA (1 << 7) /* Internal Bus Master Abort */ +#define ATUX_ISR_PMA (1 << 3) /* PCI Master Abort */ +#define ATUX_ISR_PTAM (1 << 2) /* PCI Target Abort (Master) */ +#define ATUX_ISR_PTAT (1 << 1) /* PCI Target Abort (Target) */ +#define ATUX_ISR_PMPE (1 << 0) /* PCI Master Parity Error */ +#define ATUX_ISR_ERRMSK (ATUX_ISR_PIE | ATUX_ISR_IBPR | ATUX_ISR_DCE | \ + ATUX_ISR_ISCE | ATUX_ISR_RSCE | ATUX_ISR_DPE | ATUX_ISR_IBMA | ATUX_ISR_PMA\ + | ATUX_ISR_PTAM | ATUX_ISR_PTAT | ATUX_ISR_PMPE) +#define ATUE_ISR_HON (1 << 13) /* Halt on Error Interrupt */ +#define ATUE_ISR_RSE (1 << 12) /* Root System Error Message */ +#define ATUE_ISR_REM (1 << 11) /* Root Error Message */ +#define ATUE_ISR_PIE (1 << 10) /* PCI Interface error */ +#define ATUE_ISR_CEM (1 << 9) /* Correctable Error Message */ +#define ATUE_ISR_UEM (1 << 8) /* Uncorrectable error message */ +#define ATUE_ISR_CRS (1 << 7) /* Received Configuration Retry Status */ +#define ATUE_ISR_IBMA (1 << 5) /* Internal Bus Master Abort */ +#define ATUE_ISR_DPE (1 << 4) /* Detected Parity Error Interrupt */ +#define ATUE_ISR_MAI (1 << 3) /* Received Master Abort Interrupt */ +#define ATUE_ISR_STAI (1 << 2) /* Signaled Target Abort Interrupt */ +#define ATUE_ISR_TAI (1 << 1) /* Received Target Abort Interrupt */ +#define ATUE_ISR_MDPE (1 << 0) /* Master Data Parity Error Interrupt */ +#define ATUE_ISR_ERRMSK (ATUE_ISR_HON | ATUE_ISR_RSE | ATUE_ISR_REM | \ + ATUE_ISR_PIE | ATUE_ISR_CEM | ATUE_ISR_UEM | ATUE_ISR_CRS | ATUE_ISR_IBMA |\ + ATUE_ISR_DPE | ATUE_ISR_MAI | ATUE_ISR_STAI | ATUE_ISR_TAI | ATUE_ISR_MDPE) +#define ATU_IMR 0x007c /* ATU Interrupt Mask Register */ +/* 0x0080 - 0x008f reserved */ +#define ATU_VPDCID 0x0090 /* VPD Capability Identifier Register */ +#define ATU_VPDNIP 0x0091 /* VPD Next Item Pointer Register */ +#define ATU_VPDAR 0x0092 /* VPD Address Register */ +#define ATU_VPDDR 0x0094 /* VPD Data Register */ +#define ATU_PMCID 0x0098 /* PM Capability Identifier Register */ +#define ATU_PMNIPR 0x0099 /* PM Next Item Pointer Register */ +#define ATU_PMCR 0x009a /* ATU Power Management Capabilities Register */ +#define ATU_PMCSR 0x009c /* ATU Power Management Control/Status Register*/ +#define ATU_MSICIR 0x00a0 /* MSI Capability Identifier Register */ +#define ATU_MSINIPR 0x00a1 /* MSI Next Item Pointer Register */ +#define ATU_MCR 0x00a2 /* Message Control Register */ +#define ATU_MAR 0x00a4 /* Message Address Register */ +#define ATU_MUAR 0x00a8 /* Message Upper Address Register */ +#define ATU_MDR 0x00ac /* Message Data Register */ +#define ATU_PCIXSR 0x00d4 /* PCI-X Status Register */ +#define PCIXSR_BUSNO(x) (((x) & 0xff00) >> 8) +#define ATU_IABAR3 0x0200 /* Inbound ATU Base Address Register 3 */ +#define ATU_IAUBAR3 0x0204 /* Inbound ATU Upper Base Address Register 3 */ +#define ATU_IALR3 0x0208 /* Inbound ATU Limit Register 3 */ +#define ATU_ITVR3 0x020c /* Inbound ATU Upper Translate Value Reg 3 */ +#define ATU_OIOBAR 0x0300 /* Outbound I/O Base Address Register */ +#define ATU_OIOWTVR 0x0304 /* Outbound I/O Window Translate Value Reg */ +#define ATU_OUMBAR0 0x0308 /* Outbound Upper Memory Window base addr reg 0*/ +#define ATU_OUMBAR_FUNC (28) +#define ATU_OUMBAR_EN (1U << 31) +#define ATU_OUMWTVR0 0x030c /* Outbound Upper 32bit Memory Window Translate Value Register 0 */ +#define ATU_OUMBAR1 0x0310 /* Outbound Upper Memory Window base addr reg1*/ +#define ATU_OUMWTVR1 0x0314 /* Outbound Upper 32bit Memory Window Translate Value Register 1 */ +#define ATU_OUMBAR2 0x0318 /* Outbound Upper Memory Window base addr reg2*/ +#define ATU_OUMWTVR2 0x031c /* Outbount Upper 32bit Memory Window Translate Value Register 2 */ +#define ATU_OUMBAR3 0x0320 /* Outbound Upper Memory Window base addr reg3*/ +#define ATU_OUMWTVR3 0x0324 /* Outbound Upper 32bit Memory Window Translate Value Register 3 */ + +/* ATU-X specific */ +#define ATUX_OCCAR 0x0330 /* Outbound Configuration Cycle Address Reg */ +#define ATUX_OCCDR 0x0334 /* Outbound Configuration Cycle Data Reg */ +#define ATUX_OCCFN 0x0338 /* Outbound Configuration Cycle Function Number*/ +/* ATUe specific */ +#define ATUE_OCCAR 0x032c /* Outbound Configuration Cycle Address Reg */ +#define ATUE_OCCDR 0x0330 /* Outbound Configuration Cycle Data Reg */ +#define ATUE_OCCFN 0x0334 /* Outbound Configuration Cycle Function Number*/ +/* Interrupts */ + +/* IINTRSRC0 */ +#define ICU_INT_ADMA0_EOT (0) /* ADMA 0 End of transfer */ +#define ICU_INT_ADMA0_EOC (1) /* ADMA 0 End of Chain */ +#define ICU_INT_ADMA1_EOT (2) /* ADMA 1 End of transfer */ +#define ICU_INT_ADMA1_EOC (3) /* ADMA 1 End of chain */ +#define ICU_INT_ADMA2_EOT (4) /* ADMA 2 End of transfer */ +#define ICU_INT_ADMA2_EOC (5) /* ADMA 2 end of chain */ +#define ICU_INT_WDOG (6) /* Watchdog timer */ +/* 7 Reserved */ +#define ICU_INT_TIMER0 (8) /* Timer 0 */ +#define ICU_INT_TIMER1 (9) /* Timer 1 */ +#define ICU_INT_I2C0 (10) /* I2C bus interface 0 */ +#define ICU_INT_I2C1 (11) /* I2C bus interface 1 */ +#define ICU_INT_MU (12) /* Message Unit */ +#define ICU_INT_MU_IPQ (13) /* Message unit inbound post queue */ +#define ICU_INT_ATUE_IM (14) /* ATU-E inbound message */ +#define ICU_INT_ATU_BIST (15) /* ATU/Start BIST */ +#define ICU_INT_PMC (16) /* PMC */ +#define ICU_INT_PMU (17) /* PMU */ +#define ICU_INT_PC (18) /* Processor cache */ +/* 19-23 Reserved */ +#define ICU_INT_XINT0 (24) +#define ICU_INT_XINT1 (25) +#define ICU_INT_XINT2 (26) +#define ICU_INT_XINT3 (27) +#define ICU_INT_XINT4 (28) +#define ICU_INT_XINT5 (29) +#define ICU_INT_XINT6 (30) +#define ICU_INT_XINT7 (31) +/* IINTSRC1 */ +#define ICU_INT_XINT8 (32) +#define ICU_INT_XINT9 (33) +#define ICU_INT_XINT10 (34) +#define ICU_INT_XINT11 (35) +#define ICU_INT_XINT12 (36) +#define ICU_INT_XINT13 (37) +#define ICU_INT_XINT14 (38) +#define ICU_INT_XINT15 (39) +/* 40-50 reserved */ +#define ICU_INT_UART0 (51) /* UART 0 */ +#define ICU_INT_UART1 (52) /* UART 1 */ +#define ICU_INT_PBIUE (53) /* Peripheral bus interface unit error */ +#define ICU_INT_ATUCRW (54) /* ATU Configuration register write */ +#define ICU_INT_ATUE (55) /* ATU error */ +#define ICU_INT_MCUE (56) /* Memory controller unit error */ +#define ICU_INT_ADMA0E (57) /* ADMA Channel 0 error */ +#define ICU_INT_ADMA1E (58) /* ADMA Channel 1 error */ +#define ICU_INT_ADMA2E (59) /* ADMA Channel 2 error */ +/* 60-61 reserved */ +#define ICU_INT_MUE (62) /* Messaging Unit Error */ +/* 63 reserved */ + +/* IINTSRC2 */ +#define ICU_INT_IP (64) /* Inter-processor */ +/* 65-93 reserved */ +#define ICU_INT_SIBBE (94) /* South internal bus bridge error */ +/* 95 reserved */ + +/* IINTSRC3 */ +#define ICU_INT_I2C2 (96) /* I2C bus interface 2 */ +#define ICU_INT_ATUE_BIST (97) /* ATU-E/Start BIST */ +#define ICU_INT_ATUE_CRW (98) /* ATU-E Configuration register write */ +#define ICU_INT_ATUEE (99) /* ATU-E Error */ +#define ICU_INT_IMU (100) /* IMU */ +/* 101-106 reserved */ +#define ICU_INT_ATUE_MA (107) /* ATUE Interrupt message A */ +#define ICU_INT_ATUE_MB (108) /* ATUE Interrupt message B */ +#define ICU_INT_ATUE_MC (109) /* ATUE Interrupt message C */ +#define ICU_INT_ATUE_MD (110) /* ATUE Interrupt message D */ +#define ICU_INT_MU_MSIX_TW (111) /* MU MSI-X Table write */ +/* 112 reserved */ +#define ICU_INT_IMSI (113) /* Inbound MSI */ +/* 114-126 reserved */ +#define ICU_INT_HPI (127) /* HPI */ + + +#endif /* I81342_REG_H_ */ diff --git a/sys/arm/xscale/i8134x/i81342var.h b/sys/arm/xscale/i8134x/i81342var.h new file mode 100644 index 000000000000..92574964610e --- /dev/null +++ b/sys/arm/xscale/i8134x/i81342var.h @@ -0,0 +1,72 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2006 Olivier Houchard + * 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 ``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 + * 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. + */ + +/* $FreeBSD$ */ +#ifndef I81342VAR_H_ +#define I81342VAR_H_ + +#include + +struct i81342_softc { + device_t dev; + bus_space_tag_t sc_st; + bus_space_handle_t sc_sh; + bus_space_handle_t sc_atux_sh; + bus_space_handle_t sc_atue_sh; + bus_space_tag_t sc_pciio; + bus_space_tag_t sc_pcimem; + struct rman sc_irq_rman; +}; + +struct i81342_pci_map { + vm_offset_t vaddr; + vm_paddr_t paddr; + vm_size_t size; + struct i81342_pci_map *next; +}; + +struct i81342_pci_softc { + device_t sc_dev; + bus_space_tag_t sc_st; + bus_space_handle_t sc_atu_sh; + struct bus_space sc_pciio; + struct bus_space sc_pcimem; + struct rman sc_mem_rman; + struct rman sc_io_rman; + struct rman sc_irq_rman; + char sc_is_atux; + int sc_busno; + struct i81342_pci_map *sc_pci_mappings; +}; + +void i81342_bs_init(bus_space_tag_t, void *); +void i81342_io_bs_init(bus_space_tag_t, void *); +void i81342_mem_bs_init(bus_space_tag_t, void *); +void i81342_sdram_bounds(bus_space_tag_t, bus_space_handle_t, vm_paddr_t *, + vm_size_t *); +#endif /*I81342VAR_H_ */ diff --git a/sys/arm/xscale/i8134x/iq81342_7seg.c b/sys/arm/xscale/i8134x/iq81342_7seg.c new file mode 100644 index 000000000000..7264d1c9e656 --- /dev/null +++ b/sys/arm/xscale/i8134x/iq81342_7seg.c @@ -0,0 +1,393 @@ +/* $NetBSD: iq31244_7seg.c,v 1.2 2003/07/15 00:25:01 lukem Exp $ */ + +/*- + * SPDX-License-Identifier: BSD-4-Clause + * + * 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. + */ + +/* + * Support for the 7-segment display on the Intel IQ81342. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#define WRITE(x, v) *((__volatile uint8_t *) (x)) = (v) + +static int snakestate; + +/* + * The 7-segment display looks like so: + * + * A + * +-----+ + * | | + * F | | B + * | G | + * +-----+ + * | | + * E | | C + * | D | + * +-----+ o DP + * + * Setting a bit clears the corresponding segment on the + * display. + */ +#define SEG_A (1 << 1) +#define SEG_B (1 << 2) +#define SEG_C (1 << 3) +#define SEG_D (1 << 4) +#define SEG_E (1 << 5) +#define SEG_F (1 << 6) +#define SEG_G (1 << 7) +#define SEG_DP (1 << 0) + +static const uint8_t digitmap[] = { +/* +#####+ + * # # + * # # + * # # + * +-----+ + * # # + * # # + * # # + * +#####+ + */ + (unsigned char)~SEG_G, + +/* +-----+ + * | # + * | # + * | # + * +-----+ + * | # + * | # + * | # + * +-----+ + */ + SEG_B|SEG_C, + +/* +#####+ + * | # + * | # + * | # + * +#####+ + * # | + * # | + * # | + * +#####+ + */ + ~(SEG_C|SEG_F), + +/* +#####+ + * | # + * | # + * | # + * +#####+ + * | # + * | # + * | # + * +#####+ + */ + ~(SEG_E|SEG_F), + +/* +-----+ + * # # + * # # + * # # + * +#####+ + * | # + * | # + * | # + * +-----+ + */ + ~(SEG_A|SEG_D|SEG_E), + +/* +#####+ + * # | + * # | + * # | + * +#####+ + * | # + * | # + * | # + * +#####+ + */ + ~(SEG_B|SEG_E), + +/* +#####+ + * # | + * # | + * # | + * +#####+ + * # # + * # # + * # # + * +#####+ + */ + ~(SEG_B), + +/* +#####+ + * | # + * | # + * | # + * +-----+ + * | # + * | # + * | # + * +-----+ + */ + ~(SEG_D|SEG_E|SEG_F), + +/* +#####+ + * # # + * # # + * # # + * +#####+ + * # # + * # # + * # # + * +#####+ + */ + ~0, + +/* +#####+ + * # # + * # # + * # # + * +#####+ + * | # + * | # + * | # + * +-----+ + */ + ~(SEG_D|SEG_E), +}; + +static uint8_t +iq81342_7seg_xlate(char c) +{ + uint8_t rv; + + if (c >= '0' && c <= '9') + rv = digitmap[c - '0']; + else if (c == '.') + rv = (uint8_t) ~SEG_DP; + else + rv = 0xff; + + return (rv); +} + +void +iq81342_7seg(char a, char b) +{ + uint8_t msb, lsb; + + msb = iq81342_7seg_xlate(a); + lsb = iq81342_7seg_xlate(b); + + snakestate = 0; + + WRITE(IQ8134X_7SEG_MSB, msb); + WRITE(IQ8134X_7SEG_LSB, lsb); +} + +static const uint8_t snakemap[][2] = { + +/* +#####+ +#####+ + * | | | | + * | | | | + * | | | | + * +-----+ +-----+ + * | | | | + * | | | | + * | | | | + * +-----+ +-----+ + */ + { SEG_A, SEG_A }, + +/* +-----+ +-----+ + * # | | # + * # | | # + * # | | # + * +-----+ +-----+ + * | | | | + * | | | | + * | | | | + * +-----+ +-----+ + */ + { SEG_F, SEG_B }, + +/* +-----+ +-----+ + * | | | | + * | | | | + * | | | | + * +#####+ +#####+ + * | | | | + * | | | | + * | | | | + * +-----+ +-----+ + */ + { SEG_G, SEG_G }, + +/* +-----+ +-----+ + * | | | | + * | | | | + * | | | | + * +-----+ +-----+ + * | # # | + * | # # | + * | # # | + * +-----+ +-----+ + */ + { SEG_C, SEG_E }, + +/* +-----+ +-----+ + * | | | | + * | | | | + * | | | | + * +-----+ +-----+ + * | | | | + * | | | | + * | | | | + * +#####+ +#####+ + */ + { SEG_D, SEG_D }, + +/* +-----+ +-----+ + * | | | | + * | | | | + * | | | | + * +-----+ +-----+ + * # | | # + * # | | # + * # | | # + * +-----+ +-----+ + */ + { SEG_E, SEG_C }, + +/* +-----+ +-----+ + * | | | | + * | | | | + * | | | | + * +#####+ +#####+ + * | | | | + * | | | | + * | | | | + * +-----+ +-----+ + */ + { SEG_G, SEG_G }, + +/* +-----+ +-----+ + * | # # | + * | # # | + * | # # | + * +-----+ +-----+ + * | | | | + * | | | | + * | | | | + * +-----+ +-----+ + */ + { SEG_B, SEG_F }, +}; + +static SYSCTL_NODE(_hw, OID_AUTO, sevenseg, CTLFLAG_RD, 0, "7 seg"); +static int freq = 20; +SYSCTL_INT(_hw_sevenseg, OID_AUTO, freq, CTLFLAG_RW, &freq, 0, + "7 Seg update frequency"); +static void +iq81342_7seg_snake(void) +{ + static int snakefreq; + int cur = snakestate; + + snakefreq++; + if ((snakefreq % freq)) + return; + WRITE(IQ8134X_7SEG_MSB, snakemap[cur][0]); + WRITE(IQ8134X_7SEG_LSB, snakemap[cur][1]); + + snakestate = (cur + 1) & 7; +} + +struct iq81342_7seg_softc { + device_t dev; +}; + +static int +iq81342_7seg_probe(device_t dev) +{ + + device_set_desc(dev, "IQ81342 7seg"); + return (0); +} + +extern void (*i80321_hardclock_hook)(void); +static int +iq81342_7seg_attach(device_t dev) +{ + + i80321_hardclock_hook = iq81342_7seg_snake; + return (0); +} + +static device_method_t iq81342_7seg_methods[] = { + DEVMETHOD(device_probe, iq81342_7seg_probe), + DEVMETHOD(device_attach, iq81342_7seg_attach), + {0, 0}, +}; + +static driver_t iq81342_7seg_driver = { + "iqseg", + iq81342_7seg_methods, + sizeof(struct iq81342_7seg_softc), +}; +static devclass_t iq81342_7seg_devclass; + +DRIVER_MODULE(iqseg, iq, iq81342_7seg_driver, iq81342_7seg_devclass, 0, 0); diff --git a/sys/arm/xscale/i8134x/iq81342reg.h b/sys/arm/xscale/i8134x/iq81342reg.h new file mode 100644 index 000000000000..da1e67b83f21 --- /dev/null +++ b/sys/arm/xscale/i8134x/iq81342reg.h @@ -0,0 +1,35 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2006 Olivier Houchard + * 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 ``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 + * 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. + */ + +/* $FreeBSD$ */ + +#ifndef _IQ81342REG_H_ +#define _IQ81342REG_H_ +#define IQ8134X_7SEG_MSB IOP34X_PCE1_VADDR + 0x40000 +#define IQ8134X_7SEG_LSB IOP34X_PCE1_VADDR + 0x50000 +#endif /* _IQ81342REG_H_ */ diff --git a/sys/arm/xscale/i8134x/iq81342var.h b/sys/arm/xscale/i8134x/iq81342var.h new file mode 100644 index 000000000000..8c89a0f82ef7 --- /dev/null +++ b/sys/arm/xscale/i8134x/iq81342var.h @@ -0,0 +1,34 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2006 Olivier Houchard + * 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 ``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 + * 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. + */ + +/* $FreeBSD$ */ + +#ifndef _IQ81342VAR_H_ +#define _IQ81342VAR_H_ +void iq81342_7seg(char, char); +#endif /* _I8Q1342VAR_H_ */ diff --git a/sys/arm/xscale/i8134x/obio.c b/sys/arm/xscale/i8134x/obio.c new file mode 100644 index 000000000000..f81b02795a77 --- /dev/null +++ b/sys/arm/xscale/i8134x/obio.c @@ -0,0 +1,168 @@ +/* $NetBSD: obio.c,v 1.11 2003/07/15 00:25:05 lukem Exp $ */ + +/*- + * SPDX-License-Identifier: BSD-4-Clause + * + * 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. + */ + +/* + * On-board device autoconfiguration support for Intel IQ80321 + * evaluation boards. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +static int +obio_probe(device_t dev) +{ + return (0); +} + +static int +obio_attach(device_t dev) +{ + struct obio_softc *sc = device_get_softc(dev); + + sc->oba_st = arm_base_bs_tag; + sc->oba_rman.rm_type = RMAN_ARRAY; + sc->oba_rman.rm_descr = "OBIO I/O"; + if (rman_init(&sc->oba_rman) != 0 || + rman_manage_region(&sc->oba_rman, + IOP34X_UART0_VADDR, IOP34X_UART1_VADDR + 0x40) != 0) + panic("obio_attach: failed to set up I/O rman"); + sc->oba_irq_rman.rm_type = RMAN_ARRAY; + sc->oba_irq_rman.rm_descr = "OBIO IRQ"; + if (rman_init(&sc->oba_irq_rman) != 0 || + rman_manage_region(&sc->oba_irq_rman, ICU_INT_UART0, ICU_INT_UART1) != 0) + panic("obio_attach: failed to set up IRQ rman"); + device_add_child(dev, "uart", 0); + device_add_child(dev, "uart", 1); + bus_generic_probe(dev); + bus_generic_attach(dev); + return (0); +} + +static struct resource * +obio_alloc_resource(device_t bus, device_t child, int type, int *rid, + rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) +{ + struct resource *rv; + struct rman *rm; + bus_space_tag_t bt = NULL; + bus_space_handle_t bh = 0; + struct obio_softc *sc = device_get_softc(bus); + int unit = device_get_unit(child); + + switch (type) { + case SYS_RES_IRQ: + rm = &sc->oba_irq_rman; + if (unit == 0) + start = end = ICU_INT_UART0; + else + start = end = ICU_INT_UART1; + break; + case SYS_RES_MEMORY: + return (NULL); + case SYS_RES_IOPORT: + rm = &sc->oba_rman; + bt = sc->oba_st; + if (unit == 0) { + bh = IOP34X_UART0_VADDR; + start = bh; + end = IOP34X_UART1_VADDR; + } else { + bh = IOP34X_UART1_VADDR; + start = bh; + end = start + 0x40; + } + break; + default: + return (NULL); + } + + + rv = rman_reserve_resource(rm, start, end, count, flags, child); + if (rv == NULL) + return (NULL); + if (type == SYS_RES_IRQ) + return (rv); + rman_set_rid(rv, *rid); + rman_set_bustag(rv, bt); + rman_set_bushandle(rv, bh); + + return (rv); + +} + +static int +obio_activate_resource(device_t bus, device_t child, int type, int rid, + struct resource *r) +{ + return (0); +} +static device_method_t obio_methods[] = { + DEVMETHOD(device_probe, obio_probe), + DEVMETHOD(device_attach, obio_attach), + + DEVMETHOD(bus_alloc_resource, obio_alloc_resource), + DEVMETHOD(bus_activate_resource, obio_activate_resource), + DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), + DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), + + {0, 0}, +}; + +static driver_t obio_driver = { + "obio", + obio_methods, + sizeof(struct obio_softc), +}; +static devclass_t obio_devclass; + +DRIVER_MODULE(obio, iq, obio_driver, obio_devclass, 0, 0); diff --git a/sys/arm/xscale/i8134x/obiovar.h b/sys/arm/xscale/i8134x/obiovar.h new file mode 100644 index 000000000000..fe773df10c82 --- /dev/null +++ b/sys/arm/xscale/i8134x/obiovar.h @@ -0,0 +1,56 @@ +/* $NetBSD: obiovar.h,v 1.4 2003/06/16 17:40:53 thorpej Exp $ */ + +/*- + * SPDX-License-Identifier: BSD-4-Clause + * + * Copyright (c) 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. + * + * $FreeBSD$ + * + */ + +#ifndef _IQ81342_OBIOVAR_H_ +#define _IQ81342_OBIOVAR_H_ + +#include + +struct obio_softc { + bus_space_tag_t oba_st; /* bus space tag */ + int oba_irq; /* XINT interrupt bit # */ + struct rman oba_rman; + struct rman oba_irq_rman; + +}; + +#endif /* _IQ80321_OBIOVAR_H_ */ diff --git a/sys/arm/xscale/i8134x/std.crb b/sys/arm/xscale/i8134x/std.crb new file mode 100644 index 000000000000..fe80ffb1c02e --- /dev/null +++ b/sys/arm/xscale/i8134x/std.crb @@ -0,0 +1,6 @@ +#CRB board configuration +#$FreeBSD$ +include "../xscale/i8134x/std.i81342" +files "../xscale/i8134x/files.crb" +makeoptions KERNPHYSADDR=0x00200000 +makeoptions KERNVIRTADDR=0xc0200000 diff --git a/sys/arm/xscale/i8134x/std.i81342 b/sys/arm/xscale/i8134x/std.i81342 new file mode 100644 index 000000000000..a9ad3f92a3c8 --- /dev/null +++ b/sys/arm/xscale/i8134x/std.i81342 @@ -0,0 +1,6 @@ +#XScale i81342 generic configuration +#$FreeBSD$ +files "../xscale/i8134x/files.i81342" +include "../xscale/std.xscale" +cpu CPU_XSCALE_81342 +machine arm diff --git a/sys/arm/xscale/i8134x/uart_bus_i81342.c b/sys/arm/xscale/i8134x/uart_bus_i81342.c new file mode 100644 index 000000000000..c1b39f7db55d --- /dev/null +++ b/sys/arm/xscale/i8134x/uart_bus_i81342.c @@ -0,0 +1,94 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2004 Olivier Houchard. 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 ``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 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 "uart_if.h" + +static int uart_i81342_probe(device_t dev); + +static device_method_t uart_i81342_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, uart_i81342_probe), + DEVMETHOD(device_attach, uart_bus_attach), + DEVMETHOD(device_detach, uart_bus_detach), + { 0, 0 } +}; + +static driver_t uart_i81342_driver = { + uart_driver_name, + uart_i81342_methods, + sizeof(struct uart_softc), +}; + +extern SLIST_HEAD(uart_devinfo_list, uart_devinfo) uart_sysdevs; +static int +uart_i81342_probe(device_t dev) +{ + struct uart_softc *sc; + int err; + + sc = device_get_softc(dev); + sc->sc_class = &uart_ns8250_class; + if (device_get_unit(dev) == 0) { + sc->sc_sysdev = SLIST_FIRST(&uart_sysdevs); + bcopy(&sc->sc_sysdev->bas, &sc->sc_bas, sizeof(sc->sc_bas)); + } + sc->sc_rres = bus_alloc_resource_anywhere(dev, SYS_RES_IOPORT, + &sc->sc_rrid, uart_getrange(sc->sc_class), RF_ACTIVE); + + sc->sc_bas.bsh = rman_get_bushandle(sc->sc_rres); + sc->sc_bas.bst = rman_get_bustag(sc->sc_rres); + bus_space_write_4(sc->sc_bas.bst, sc->sc_bas.bsh, REG_IER << 2, + 0x40 | 0x10); + bus_release_resource(dev, sc->sc_rtype, sc->sc_rrid, sc->sc_rres); + + err = uart_bus_probe(dev, 2, 0, 33334000, 0, device_get_unit(dev)); + sc->sc_rxfifosz = sc->sc_txfifosz = 1; + return (err); +} + + +DRIVER_MODULE(uart, obio, uart_i81342_driver, uart_devclass, 0, 0); diff --git a/sys/arm/xscale/i8134x/uart_cpu_i81342.c b/sys/arm/xscale/i8134x/uart_cpu_i81342.c new file mode 100644 index 000000000000..59bd47602186 --- /dev/null +++ b/sys/arm/xscale/i8134x/uart_cpu_i81342.c @@ -0,0 +1,70 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2003 Marcel Moolenaar + * 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 ``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 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; + +int +uart_cpu_eqres(struct uart_bas *b1, struct uart_bas *b2) +{ + return ((b1->bsh == b2->bsh && b1->bst == b2->bst) ? 1 : 0); +} + +int +uart_cpu_getdev(int devtype, struct uart_devinfo *di) +{ + + di->ops = uart_getops(&uart_ns8250_class); + di->bas.chan = 0; + di->bas.bst = arm_base_bs_tag; + di->bas.regshft = 2; + di->bas.rclk = 33334000; + di->baudrate = 115200; + di->databits = 8; + di->stopbits = 1; + di->parity = UART_PARITY_NONE; + uart_bus_space_io = arm_base_bs_tag; + uart_bus_space_mem = NULL; + di->bas.bsh = IOP34X_UART0_VADDR; + return (0); +} diff --git a/sys/arm/xscale/pxa/files.pxa b/sys/arm/xscale/pxa/files.pxa new file mode 100644 index 000000000000..652877060dcb --- /dev/null +++ b/sys/arm/xscale/pxa/files.pxa @@ -0,0 +1,14 @@ +# $FreeBSD$ + +arm/xscale/pxa/pxa_gpio.c standard +arm/xscale/pxa/pxa_icu.c standard +arm/xscale/pxa/pxa_machdep.c standard +arm/xscale/pxa/pxa_obio.c standard +arm/xscale/pxa/pxa_smi.c standard +arm/xscale/pxa/pxa_space.c standard +arm/xscale/pxa/pxa_timer.c standard + +arm/xscale/pxa/uart_bus_pxa.c optional uart +arm/xscale/pxa/uart_cpu_pxa.c optional uart + +arm/xscale/pxa/if_smc_smi.c optional smc diff --git a/sys/arm/xscale/pxa/if_smc_smi.c b/sys/arm/xscale/pxa/if_smc_smi.c new file mode 100644 index 000000000000..4b9c58d8d865 --- /dev/null +++ b/sys/arm/xscale/pxa/if_smc_smi.c @@ -0,0 +1,127 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2008 Benno Rice + * 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 ``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 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 "miibus_if.h" + +#include +#include + +static int smc_smi_probe(device_t); +static int smc_smi_attach(device_t); +static int smc_smi_detach(device_t); + +static int +smc_smi_probe(device_t dev) +{ + struct smc_softc *sc; + + sc = device_get_softc(dev); + sc->smc_usemem = 1; + + if (smc_probe(dev) != 0) { + return (ENXIO); + } + return (0); +} + +static int +smc_smi_attach(device_t dev) +{ + int err; + struct smc_softc *sc; + + sc = device_get_softc(dev); + + err = smc_attach(dev); + if (err) { + return (err); + } + + return (0); +} + +static int +smc_smi_detach(device_t dev) +{ + + smc_detach(dev); + + return (0); +} + +static device_method_t smc_smi_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, smc_smi_probe), + DEVMETHOD(device_attach, smc_smi_attach), + DEVMETHOD(device_detach, smc_smi_detach), + + /* MII interface */ + DEVMETHOD(miibus_readreg, smc_miibus_readreg), + DEVMETHOD(miibus_writereg, smc_miibus_writereg), + DEVMETHOD(miibus_statchg, smc_miibus_statchg), + + { 0, 0 } +}; + +static driver_t smc_smi_driver = { + "smc", + smc_smi_methods, + sizeof(struct smc_softc), +}; + +extern devclass_t smc_devclass; + +DRIVER_MODULE(smc, smi, smc_smi_driver, smc_devclass, 0, 0); +DRIVER_MODULE(miibus, smc, miibus_driver, miibus_devclass, 0, 0); +MODULE_DEPEND(smc, smi, 1, 1, 1); +MODULE_DEPEND(smc, ether, 1, 1, 1); +MODULE_DEPEND(smc, miibus, 1, 1, 1); diff --git a/sys/arm/xscale/pxa/pxa_gpio.c b/sys/arm/xscale/pxa/pxa_gpio.c new file mode 100644 index 000000000000..91f3865d3ba5 --- /dev/null +++ b/sys/arm/xscale/pxa/pxa_gpio.c @@ -0,0 +1,360 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2006 Benno Rice. 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 ``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 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 + +struct pxa_gpio_softc { + struct resource * pg_res[4]; + bus_space_tag_t pg_bst; + bus_space_handle_t pg_bsh; + struct mtx pg_mtx; + + uint32_t pg_intr[3]; +}; + +static struct resource_spec pxa_gpio_spec[] = { + { SYS_RES_MEMORY, 0, RF_ACTIVE }, + { SYS_RES_IRQ, 0, RF_ACTIVE }, + { SYS_RES_IRQ, 1, RF_ACTIVE }, + { SYS_RES_IRQ, 2, RF_ACTIVE }, + { -1, 0 } +}; + +static struct pxa_gpio_softc *pxa_gpio_softc = NULL; + +static int pxa_gpio_probe(device_t); +static int pxa_gpio_attach(device_t); + +static driver_filter_t pxa_gpio_intr0; +static driver_filter_t pxa_gpio_intr1; +static driver_filter_t pxa_gpio_intrN; + +static int +pxa_gpio_probe(device_t dev) +{ + + device_set_desc(dev, "GPIO Controller"); + return (0); +} + +static int +pxa_gpio_attach(device_t dev) +{ + int error; + void *ihl; + struct pxa_gpio_softc *sc; + + sc = (struct pxa_gpio_softc *)device_get_softc(dev); + + if (pxa_gpio_softc != NULL) + return (ENXIO); + pxa_gpio_softc = sc; + + error = bus_alloc_resources(dev, pxa_gpio_spec, sc->pg_res); + if (error) { + device_printf(dev, "could not allocate resources\n"); + return (ENXIO); + } + + sc->pg_bst = rman_get_bustag(sc->pg_res[0]); + sc->pg_bsh = rman_get_bushandle(sc->pg_res[0]); + + /* Disable and clear all interrupts. */ + bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GRER0, 0); + bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GRER1, 0); + bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GRER2, 0); + bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GFER0, 0); + bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GFER1, 0); + bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GFER2, 0); + bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR0, ~0); + bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR1, ~0); + bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR2, ~0); + + mtx_init(&sc->pg_mtx, "GPIO mutex", NULL, MTX_SPIN); + + if (bus_setup_intr(dev, sc->pg_res[1], INTR_TYPE_MISC|INTR_MPSAFE, + pxa_gpio_intr0, NULL, sc, &ihl) != 0) { + bus_release_resources(dev, pxa_gpio_spec, sc->pg_res); + device_printf(dev, "could not set up intr0\n"); + return (ENXIO); + } + + if (bus_setup_intr(dev, sc->pg_res[2], INTR_TYPE_MISC|INTR_MPSAFE, + pxa_gpio_intr1, NULL, sc, &ihl) != 0) { + bus_release_resources(dev, pxa_gpio_spec, sc->pg_res); + device_printf(dev, "could not set up intr1\n"); + return (ENXIO); + } + + if (bus_setup_intr(dev, sc->pg_res[3], INTR_TYPE_MISC|INTR_MPSAFE, + pxa_gpio_intrN, NULL, sc, &ihl) != 0) { + bus_release_resources(dev, pxa_gpio_spec, sc->pg_res); + device_printf(dev, "could not set up intrN\n"); + return (ENXIO); + } + + return (0); +} + +static int +pxa_gpio_intr0(void *arg) +{ + struct pxa_gpio_softc *sc; + + sc = (struct pxa_gpio_softc *)arg; + + bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR0, 0x1); + sc->pg_intr[0] |= 1; + + return (FILTER_HANDLED); +} + +static int +pxa_gpio_intr1(void *arg) +{ + struct pxa_gpio_softc *sc; + + sc = (struct pxa_gpio_softc *)arg; + + bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR0, 0x2); + sc->pg_intr[1] |= 2; + + return (FILTER_HANDLED); +} + +static int +pxa_gpio_intrN(void *arg) +{ + uint32_t gedr0, gedr1, gedr2; + struct pxa_gpio_softc *sc; + + sc = (struct pxa_gpio_softc *)arg; + + gedr0 = bus_space_read_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR0); + gedr0 &= 0xfffffffc; + bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR0, gedr0); + + gedr1 = bus_space_read_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR1); + bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR1, gedr1); + + gedr2 = bus_space_read_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR2); + gedr2 &= 0x001fffff; + bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR2, gedr2); + + sc->pg_intr[0] |= gedr0; + sc->pg_intr[1] |= gedr1; + sc->pg_intr[2] |= gedr2; + + return (FILTER_HANDLED); +} + +static device_method_t pxa_gpio_methods[] = { + DEVMETHOD(device_probe, pxa_gpio_probe), + DEVMETHOD(device_attach, pxa_gpio_attach), + + {0, 0} +}; + +static driver_t pxa_gpio_driver = { + "gpio", + pxa_gpio_methods, + sizeof(struct pxa_gpio_softc), +}; + +static devclass_t pxa_gpio_devclass; + +DRIVER_MODULE(pxagpio, pxa, pxa_gpio_driver, pxa_gpio_devclass, 0, 0); + +#define pxagpio_reg_read(softc, reg) \ + bus_space_read_4(sc->pg_bst, sc->pg_bsh, reg) +#define pxagpio_reg_write(softc, reg, val) \ + bus_space_write_4(sc->pg_bst, sc->pg_bsh, reg, val) + +uint32_t +pxa_gpio_get_function(int gpio) +{ + struct pxa_gpio_softc *sc; + uint32_t rv, io; + + sc = pxa_gpio_softc; + + rv = pxagpio_reg_read(sc, GPIO_FN_REG(gpio)) >> GPIO_FN_SHIFT(gpio); + rv = GPIO_FN(rv); + + io = pxagpio_reg_read(sc, PXA250_GPIO_REG(GPIO_GPDR0, gpio)); + if (io & GPIO_BIT(gpio)) + rv |= GPIO_OUT; + + io = pxagpio_reg_read(sc, PXA250_GPIO_REG(GPIO_GPLR0, gpio)); + if (io & GPIO_BIT(gpio)) + rv |= GPIO_SET; + + return (rv); +} + +uint32_t +pxa_gpio_set_function(int gpio, uint32_t fn) +{ + struct pxa_gpio_softc *sc; + uint32_t rv, bit, oldfn; + + sc = pxa_gpio_softc; + + oldfn = pxa_gpio_get_function(gpio); + + if (GPIO_FN(fn) == GPIO_FN(oldfn) && + GPIO_FN_IS_OUT(fn) == GPIO_FN_IS_OUT(oldfn)) { + /* + * The pin's function is not changing. + * For Alternate Functions and GPIO input, we can just + * return now. + * For GPIO output pins, check the initial state is + * the same. + * + * Return 'fn' instead of 'oldfn' so the caller can + * reliably detect that we didn't change anything. + * (The initial state might be different for non- + * GPIO output pins). + */ + if (!GPIO_IS_GPIO_OUT(fn) || + GPIO_FN_IS_SET(fn) == GPIO_FN_IS_SET(oldfn)) + return (fn); + } + + /* + * See section 4.1.3.7 of the PXA2x0 Developer's Manual for + * the correct procedure for changing GPIO pin functions. + */ + + bit = GPIO_BIT(gpio); + + /* + * 1. Configure the correct set/clear state of the pin + */ + if (GPIO_FN_IS_SET(fn)) + pxagpio_reg_write(sc, PXA250_GPIO_REG(GPIO_GPSR0, gpio), bit); + else + pxagpio_reg_write(sc, PXA250_GPIO_REG(GPIO_GPCR0, gpio), bit); + + /* + * 2. Configure the pin as an input or output as appropriate + */ + rv = pxagpio_reg_read(sc, PXA250_GPIO_REG(GPIO_GPDR0, gpio)) & ~bit; + if (GPIO_FN_IS_OUT(fn)) + rv |= bit; + pxagpio_reg_write(sc, PXA250_GPIO_REG(GPIO_GPDR0, gpio), rv); + + /* + * 3. Configure the pin's function + */ + bit = GPIO_FN_MASK << GPIO_FN_SHIFT(gpio); + fn = GPIO_FN(fn) << GPIO_FN_SHIFT(gpio); + rv = pxagpio_reg_read(sc, GPIO_FN_REG(gpio)) & ~bit; + pxagpio_reg_write(sc, GPIO_FN_REG(gpio), rv | fn); + + return (oldfn); +} + +/* + * GPIO "interrupt" handling. + */ + +void +pxa_gpio_mask_irq(int irq) +{ + uint32_t val; + struct pxa_gpio_softc *sc; + int gpio; + + sc = pxa_gpio_softc; + gpio = IRQ_TO_GPIO(irq); + + val = pxagpio_reg_read(sc, PXA250_GPIO_REG(GPIO_GRER0, gpio)); + val &= ~GPIO_BIT(gpio); + pxagpio_reg_write(sc, PXA250_GPIO_REG(GPIO_GRER0, gpio), val); +} + +void +pxa_gpio_unmask_irq(int irq) +{ + uint32_t val; + struct pxa_gpio_softc *sc; + int gpio; + + sc = pxa_gpio_softc; + gpio = IRQ_TO_GPIO(irq); + + val = pxagpio_reg_read(sc, PXA250_GPIO_REG(GPIO_GRER0, gpio)); + val |= GPIO_BIT(gpio); + pxagpio_reg_write(sc, PXA250_GPIO_REG(GPIO_GRER0, gpio), val); +} + +int +pxa_gpio_get_next_irq(void) +{ + struct pxa_gpio_softc *sc; + int gpio; + + sc = pxa_gpio_softc; + + if (sc->pg_intr[0] != 0) { + gpio = ffs(sc->pg_intr[0]) - 1; + sc->pg_intr[0] &= ~(1 << gpio); + return (GPIO_TO_IRQ(gpio)); + } + if (sc->pg_intr[1] != 0) { + gpio = ffs(sc->pg_intr[1]) - 1; + sc->pg_intr[1] &= ~(1 << gpio); + return (GPIO_TO_IRQ(gpio + 32)); + } + if (sc->pg_intr[2] != 0) { + gpio = ffs(sc->pg_intr[2]) - 1; + sc->pg_intr[2] &= ~(1 << gpio); + return (GPIO_TO_IRQ(gpio + 64)); + } + + return (-1); +} diff --git a/sys/arm/xscale/pxa/pxa_icu.c b/sys/arm/xscale/pxa/pxa_icu.c new file mode 100644 index 000000000000..d39fa3e09c7a --- /dev/null +++ b/sys/arm/xscale/pxa/pxa_icu.c @@ -0,0 +1,261 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2006 Benno Rice. 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 ``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 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 + +struct pxa_icu_softc { + struct resource * pi_res[1]; + bus_space_tag_t pi_bst; + bus_space_handle_t pi_bsh; +}; + +static struct resource_spec pxa_icu_spec[] = { + { SYS_RES_MEMORY, 0, RF_ACTIVE }, + { -1, 0 } +}; + +static struct pxa_icu_softc *pxa_icu_softc = NULL; + +static int pxa_icu_probe(device_t); +static int pxa_icu_attach(device_t); + +uint32_t pxa_icu_get_icip(void); +void pxa_icu_clear_icip(int); +uint32_t pxa_icu_get_icfp(void); +void pxa_icu_clear_icfp(int); +uint32_t pxa_icu_get_icmr(void); +void pxa_icu_set_icmr(uint32_t); +uint32_t pxa_icu_get_iclr(void); +void pxa_icu_set_iclr(uint32_t); +uint32_t pxa_icu_get_icpr(void); +void pxa_icu_idle_enable(void); +void pxa_icu_idle_disable(void); + +extern uint32_t pxa_gpio_intr_flags[]; + +static int +pxa_icu_probe(device_t dev) +{ + + device_set_desc(dev, "Interrupt Controller"); + return (0); +} + +static int +pxa_icu_attach(device_t dev) +{ + int error; + struct pxa_icu_softc *sc; + + sc = (struct pxa_icu_softc *)device_get_softc(dev); + + if (pxa_icu_softc != NULL) + return (ENXIO); + pxa_icu_softc = sc; + + error = bus_alloc_resources(dev, pxa_icu_spec, sc->pi_res); + if (error) { + device_printf(dev, "could not allocate resources\n"); + return (ENXIO); + } + + sc->pi_bst = rman_get_bustag(sc->pi_res[0]); + sc->pi_bsh = rman_get_bushandle(sc->pi_res[0]); + + /* Disable all interrupts. */ + pxa_icu_set_icmr(0); + + /* Route all interrupts to IRQ rather than FIQ. */ + pxa_icu_set_iclr(0); + + /* XXX: This should move to configure_final or something. */ + enable_interrupts(PSR_I|PSR_F); + + return (0); +} + +static device_method_t pxa_icu_methods[] = { + DEVMETHOD(device_probe, pxa_icu_probe), + DEVMETHOD(device_attach, pxa_icu_attach), + + {0, 0} +}; + +static driver_t pxa_icu_driver = { + "icu", + pxa_icu_methods, + sizeof(struct pxa_icu_softc), +}; + +static devclass_t pxa_icu_devclass; + +DRIVER_MODULE(pxaicu, pxa, pxa_icu_driver, pxa_icu_devclass, 0, 0); + +int +arm_get_next_irq(int last __unused) +{ + int irq; + + if ((irq = pxa_icu_get_icip()) != 0) { + return (ffs(irq) - 1); + } + + return (pxa_gpio_get_next_irq()); +} + +void +arm_mask_irq(uintptr_t nb) +{ + uint32_t mr; + + if (nb >= IRQ_GPIO0) { + pxa_gpio_mask_irq(nb); + return; + } + + mr = pxa_icu_get_icmr(); + mr &= ~(1 << nb); + pxa_icu_set_icmr(mr); +} + +void +arm_unmask_irq(uintptr_t nb) +{ + uint32_t mr; + + if (nb >= IRQ_GPIO0) { + pxa_gpio_unmask_irq(nb); + return; + } + + mr = pxa_icu_get_icmr(); + mr |= (1 << nb); + pxa_icu_set_icmr(mr); +} + +uint32_t +pxa_icu_get_icip(void) +{ + + return (bus_space_read_4(pxa_icu_softc->pi_bst, + pxa_icu_softc->pi_bsh, ICU_IP)); +} + +void +pxa_icu_clear_icip(int irq) +{ + + bus_space_write_4(pxa_icu_softc->pi_bst, + pxa_icu_softc->pi_bsh, ICU_IP, (1 << irq)); +} + +uint32_t +pxa_icu_get_icfp(void) +{ + + return (bus_space_read_4(pxa_icu_softc->pi_bst, + pxa_icu_softc->pi_bsh, ICU_FP)); +} + +void +pxa_icu_clear_icfp(int irq) +{ + + bus_space_write_4(pxa_icu_softc->pi_bst, + pxa_icu_softc->pi_bsh, ICU_FP, (1 << irq)); +} + +uint32_t +pxa_icu_get_icmr(void) +{ + + return (bus_space_read_4(pxa_icu_softc->pi_bst, + pxa_icu_softc->pi_bsh, ICU_MR)); +} + +void +pxa_icu_set_icmr(uint32_t val) +{ + + bus_space_write_4(pxa_icu_softc->pi_bst, + pxa_icu_softc->pi_bsh, ICU_MR, val); +} + +uint32_t +pxa_icu_get_iclr(void) +{ + + return (bus_space_read_4(pxa_icu_softc->pi_bst, + pxa_icu_softc->pi_bsh, ICU_LR)); +} + +void +pxa_icu_set_iclr(uint32_t val) +{ + + bus_space_write_4(pxa_icu_softc->pi_bst, + pxa_icu_softc->pi_bsh, ICU_LR, val); +} + +uint32_t +pxa_icu_get_icpr(void) +{ + + return (bus_space_read_4(pxa_icu_softc->pi_bst, + pxa_icu_softc->pi_bsh, ICU_PR)); +} + +void +pxa_icu_idle_enable(void) +{ + + bus_space_write_4(pxa_icu_softc->pi_bst, + pxa_icu_softc->pi_bsh, ICU_CR, 0x0); +} + +void +pxa_icu_idle_disable(void) +{ + + bus_space_write_4(pxa_icu_softc->pi_bst, + pxa_icu_softc->pi_bsh, ICU_CR, 0x1); +} diff --git a/sys/arm/xscale/pxa/pxa_machdep.c b/sys/arm/xscale/pxa/pxa_machdep.c new file mode 100644 index 000000000000..e28599be9bfd --- /dev/null +++ b/sys/arm/xscale/pxa/pxa_machdep.c @@ -0,0 +1,439 @@ +/* $NetBSD: hpc_machdep.c,v 1.70 2003/09/16 08:18:22 agc Exp $ */ + +/*- + * SPDX-License-Identifier: BSD-4-Clause + * + * Copyright (c) 1994-1998 Mark Brinicombe. + * Copyright (c) 1994 Brini. + * All rights reserved. + * + * This code is derived from software written for Brini by Mark Brinicombe + * + * 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 Brini. + * 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 BRINI ``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 BRINI 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. + * + * RiscBSD kernel project + * + * machdep.c + * + * Machine dependent functions for kernel setup + * + * This file needs a lot of work. + * + * Created : 17/09/94 + */ + +#include "opt_ddb.h" +#include "opt_kstack_pages.h" + +#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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define KERNEL_PT_SYS 0 /* Page table for mapping proc0 zero page */ +#define KERNEL_PT_IOPXS 1 +#define KERNEL_PT_BEFOREKERN 2 +#define KERNEL_PT_AFKERNEL 3 /* L2 table for mapping after kernel */ +#define KERNEL_PT_AFKERNEL_NUM 9 + +/* 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) + +struct pv_addr kernel_pt_table[NUM_KERNEL_PTS]; + +/* Physical and virtual addresses for some global pages */ + +struct pv_addr systempage; +struct pv_addr msgbufpv; +struct pv_addr irqstack; +struct pv_addr undstack; +struct pv_addr abtstack; +struct pv_addr kernelstack; +struct pv_addr minidataclean; + +static void pxa_probe_sdram(bus_space_tag_t, bus_space_handle_t, + uint32_t *, uint32_t *); + +/* Static device mappings. */ +static const struct devmap_entry pxa_devmap[] = { + /* + * Map the on-board devices up into the KVA region so we don't muck + * up user-space. + */ + { + PXA2X0_PERIPH_START + PXA2X0_PERIPH_OFFSET, + PXA2X0_PERIPH_START, + PXA250_PERIPH_END - PXA2X0_PERIPH_START, + }, + { 0, 0, 0, } +}; + +#define SDRAM_START 0xa0000000 + +extern vm_offset_t xscale_cache_clean_addr; + +void * +initarm(struct arm_boot_params *abp) +{ + struct pv_addr kernel_l1pt; + struct pv_addr dpcpu; + int loop; + u_int l1pagetable; + vm_offset_t freemempos; + vm_offset_t freemem_pt; + vm_offset_t afterkern; + vm_offset_t freemem_after; + vm_offset_t lastaddr; + int i, j; + uint32_t memsize[PXA2X0_SDRAM_BANKS], memstart[PXA2X0_SDRAM_BANKS]; + + lastaddr = parse_boot_param(abp); + arm_physmem_kernaddr = abp->abp_physaddr; + set_cpufuncs(); + pcpu_init(pcpup, 0, sizeof(struct pcpu)); + PCPU_SET(curthread, &thread0); + + /* Do basic tuning, hz etc */ + init_param1(); + + freemempos = 0xa0200000; + /* Define a macro to simplify memory allocation */ +#define valloc_pages(var, np) \ + alloc_pages((var).pv_pa, (np)); \ + (var).pv_va = (var).pv_pa + 0x20000000; + +#define alloc_pages(var, np) \ + freemempos -= (np * PAGE_SIZE); \ + (var) = freemempos; \ + memset((char *)(var), 0, ((np) * PAGE_SIZE)); + + while (((freemempos - L1_TABLE_SIZE) & (L1_TABLE_SIZE - 1)) != 0) + freemempos -= PAGE_SIZE; + valloc_pages(kernel_l1pt, L1_TABLE_SIZE / PAGE_SIZE); + for (loop = 0; loop < NUM_KERNEL_PTS; ++loop) { + if (!(loop % (PAGE_SIZE / L2_TABLE_SIZE_REAL))) { + valloc_pages(kernel_pt_table[loop], + L2_TABLE_SIZE / PAGE_SIZE); + } else { + kernel_pt_table[loop].pv_pa = freemempos + + (loop % (PAGE_SIZE / L2_TABLE_SIZE_REAL)) * + L2_TABLE_SIZE_REAL; + kernel_pt_table[loop].pv_va = + kernel_pt_table[loop].pv_pa + 0x20000000; + } + } + freemem_pt = freemempos; + freemempos = 0xa0100000; + /* + * Allocate a page for the system page mapped to V0x00000000 + * This page will just contain the system vectors and can be + * shared by all processes. + */ + valloc_pages(systempage, 1); + + /* Allocate dynamic per-cpu area. */ + valloc_pages(dpcpu, DPCPU_SIZE / PAGE_SIZE); + dpcpu_init((void *)dpcpu.pv_va, 0); + + /* Allocate stacks for all modes */ + valloc_pages(irqstack, IRQ_STACK_SIZE); + valloc_pages(abtstack, ABT_STACK_SIZE); + valloc_pages(undstack, UND_STACK_SIZE); + valloc_pages(kernelstack, kstack_pages); + alloc_pages(minidataclean.pv_pa, 1); + valloc_pages(msgbufpv, round_page(msgbufsize) / PAGE_SIZE); + /* + * Allocate memory for the l1 and l2 page tables. The scheme to avoid + * wasting memory by allocating the l1pt on the first 16k memory was + * taken from NetBSD rpc_machdep.c. NKPT should be greater than 12 for + * this to work (which is supposed to be the case). + */ + + /* + * Now we start construction of the L1 page table + * We start by mapping the L2 page tables into the L1. + * This means that we can replace L1 mappings later on if necessary + */ + l1pagetable = kernel_l1pt.pv_va; + + /* Map the L2 pages tables in the L1 page table */ + pmap_link_l2pt(l1pagetable, rounddown2(ARM_VECTORS_HIGH, 0x00100000), + &kernel_pt_table[KERNEL_PT_SYS]); +#if 0 /* XXXBJR: What is this? Don't know if there's an analogue. */ + pmap_link_l2pt(l1pagetable, IQ80321_IOPXS_VBASE, + &kernel_pt_table[KERNEL_PT_IOPXS]); +#endif + pmap_link_l2pt(l1pagetable, KERNBASE, + &kernel_pt_table[KERNEL_PT_BEFOREKERN]); + pmap_map_chunk(l1pagetable, KERNBASE, SDRAM_START, 0x100000, + VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); + pmap_map_chunk(l1pagetable, KERNBASE + 0x100000, SDRAM_START + 0x100000, + 0x100000, VM_PROT_READ|VM_PROT_WRITE, PTE_PAGETABLE); + pmap_map_chunk(l1pagetable, KERNBASE + 0x200000, SDRAM_START + 0x200000, + rounddown2(((uint32_t)(lastaddr) - KERNBASE - 0x200000) + L1_S_SIZE, L1_S_SIZE), + VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); + freemem_after = rounddown2((int)lastaddr + PAGE_SIZE, PAGE_SIZE); + afterkern = round_page(rounddown2((vm_offset_t)lastaddr + L1_S_SIZE, L1_S_SIZE)); + for (i = 0; i < KERNEL_PT_AFKERNEL_NUM; i++) { + pmap_link_l2pt(l1pagetable, afterkern + i * 0x00100000, + &kernel_pt_table[KERNEL_PT_AFKERNEL + i]); + } + pmap_map_entry(l1pagetable, afterkern, minidataclean.pv_pa, + VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); + + + /* Map the Mini-Data cache clean area. */ + xscale_setup_minidata(l1pagetable, afterkern, + minidataclean.pv_pa); + + /* Map the vector page. */ + pmap_map_entry(l1pagetable, ARM_VECTORS_HIGH, systempage.pv_pa, + VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); + devmap_bootstrap(l1pagetable, pxa_devmap); + + /* + * Give the XScale global cache clean code an appropriately + * sized chunk of unmapped VA space starting at 0xff000000 + * (our device mappings end before this address). + */ + xscale_cache_clean_addr = 0xff000000U; + + cpu_domains((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT); + cpu_setttb(kernel_l1pt.pv_pa); + cpu_tlb_flushID(); + cpu_domains(DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)); + + /* + * Pages were allocated during the secondary bootstrap for the + * stacks for different CPU modes. + * We must now set the r13 registers in the different CPU modes to + * point to these stacks. + * Since the ARM stacks use STMFD etc. we must set r13 to the top end + * of the stack memory. + */ + set_stackptrs(0); + + /* + * We must now clean the cache again.... + * Cleaning may be done by reading new data to displace any + * dirty data in the cache. This will have happened in cpu_setttb() + * but since we are boot strapping the addresses used for the read + * may have just been remapped and thus the cache could be out + * of sync. A re-clean after the switch will cure this. + * After booting there are no gross relocations of the kernel thus + * this problem will not occur after initarm(). + */ + cpu_idcache_wbinv_all(); + cpu_setup(); + + /* + * Sort out bus_space for on-board devices. + */ + pxa_obio_tag_init(); + + /* + * Fetch the SDRAM start/size from the PXA2X0 SDRAM configration + * registers. + */ + pxa_probe_sdram(obio_tag, PXA2X0_MEMCTL_BASE, memstart, memsize); + + /* Fire up consoles. */ + cninit(); + + undefined_init(); + + init_proc0(kernelstack.pv_va); + + /* Enable MMU, I-cache, D-cache, write buffer. */ + arm_vector_init(ARM_VECTORS_HIGH, ARM_VEC_ALL); + + pmap_curmaxkvaddr = afterkern + PAGE_SIZE; + vm_max_kernel_address = 0xe0000000; + pmap_bootstrap(pmap_curmaxkvaddr, &kernel_l1pt); + msgbufp = (void*)msgbufpv.pv_va; + msgbufinit(msgbufp, msgbufsize); + mutex_init(); + + /* + * Add the physical ram we have available. + * + * Exclude the kernel (and all the things we allocated which immediately + * follow the kernel) from the VM allocation pool but not from crash + * dumps. virtual_avail is a global variable which tracks the kva we've + * "allocated" while setting up pmaps. + * + * Prepare the list of physical memory available to the vm subsystem. + */ + for (j = 0; j < PXA2X0_SDRAM_BANKS; j++) { + if (memsize[j] > 0) + arm_physmem_hardware_region(memstart[j], memsize[j]); + } + arm_physmem_exclude_region(freemem_pt, abp->abp_physaddr - + freemem_pt, EXFLAG_NOALLOC); + arm_physmem_exclude_region(freemempos, abp->abp_physaddr - 0x100000 - + freemempos, EXFLAG_NOALLOC); + arm_physmem_exclude_region(abp->abp_physaddr, + virtual_avail - KERNVIRTADDR, EXFLAG_NOALLOC); + arm_physmem_init_kernel_globals(); + + init_param2(physmem); + kdb_init(); + return ((void *)(kernelstack.pv_va + USPACE_SVC_STACK_TOP - + sizeof(struct pcb))); +} + +static void +pxa_probe_sdram(bus_space_tag_t bst, bus_space_handle_t bsh, + uint32_t *memstart, uint32_t *memsize) +{ + uint32_t mdcnfg, dwid, dcac, drac, dnb; + int i; + + mdcnfg = bus_space_read_4(bst, bsh, MEMCTL_MDCNFG); + + /* + * Scan all 4 SDRAM banks + */ + for (i = 0; i < PXA2X0_SDRAM_BANKS; i++) { + memstart[i] = 0; + memsize[i] = 0; + + switch (i) { + case 0: + case 1: + if ((i == 0 && (mdcnfg & MDCNFG_DE0) == 0) || + (i == 1 && (mdcnfg & MDCNFG_DE1) == 0)) + continue; + dwid = mdcnfg >> MDCNFD_DWID01_SHIFT; + dcac = mdcnfg >> MDCNFD_DCAC01_SHIFT; + drac = mdcnfg >> MDCNFD_DRAC01_SHIFT; + dnb = mdcnfg >> MDCNFD_DNB01_SHIFT; + break; + + case 2: + case 3: + if ((i == 2 && (mdcnfg & MDCNFG_DE2) == 0) || + (i == 3 && (mdcnfg & MDCNFG_DE3) == 0)) + continue; + dwid = mdcnfg >> MDCNFD_DWID23_SHIFT; + dcac = mdcnfg >> MDCNFD_DCAC23_SHIFT; + drac = mdcnfg >> MDCNFD_DRAC23_SHIFT; + dnb = mdcnfg >> MDCNFD_DNB23_SHIFT; + break; + default: + panic("pxa_probe_sdram: impossible"); + } + + dwid = 2 << (1 - (dwid & MDCNFD_DWID_MASK)); /* 16/32 width */ + dcac = 1 << ((dcac & MDCNFD_DCAC_MASK) + 8); /* 8-11 columns */ + drac = 1 << ((drac & MDCNFD_DRAC_MASK) + 11); /* 11-13 rows */ + dnb = 2 << (dnb & MDCNFD_DNB_MASK); /* # of banks */ + + memsize[i] = dwid * dcac * drac * dnb; + memstart[i] = PXA2X0_SDRAM0_START + + (i * PXA2X0_SDRAM_BANK_SIZE); + } +} + +#define TIMER_FREQUENCY 3686400 +#define UNIMPLEMENTED panic("%s: unimplemented", __func__) + +/* XXXBJR: Belongs with DELAY in a timer.c of some sort. */ +void +cpu_startprofclock(void) +{ + UNIMPLEMENTED; +} + +void +cpu_stopprofclock(void) +{ + UNIMPLEMENTED; +} + +static struct arm32_dma_range pxa_range = { + .dr_sysbase = 0, + .dr_busbase = 0, + .dr_len = ~0u, +}; + +struct arm32_dma_range * +bus_dma_get_range(void) +{ + + return (&pxa_range); +} + +int +bus_dma_get_range_nb(void) +{ + + return (1); +} diff --git a/sys/arm/xscale/pxa/pxa_obio.c b/sys/arm/xscale/pxa/pxa_obio.c new file mode 100644 index 000000000000..e084a3b49471 --- /dev/null +++ b/sys/arm/xscale/pxa/pxa_obio.c @@ -0,0 +1,399 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2006 Benno Rice. 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 ``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 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 + +static void pxa_identify(driver_t *, device_t); +static int pxa_probe(device_t); +static int pxa_attach(device_t); + +static int pxa_print_child(device_t, device_t); + +static int pxa_setup_intr(device_t, device_t, struct resource *, int, + driver_filter_t *, driver_intr_t *, void *, void **); +static int pxa_read_ivar(device_t, device_t, int, uintptr_t *); + +static struct resource_list * pxa_get_resource_list(device_t, device_t); +static struct resource * pxa_alloc_resource(device_t, device_t, int, + int *, rman_res_t, rman_res_t, rman_res_t, u_int); +static int pxa_release_resource(device_t, device_t, int, + int, struct resource *); +static int pxa_activate_resource(device_t, device_t, + int, int, struct resource *); + +static struct resource * pxa_alloc_gpio_irq(device_t, device_t, int, + int *, rman_res_t, rman_res_t, rman_res_t, u_int); + +struct obio_device { + const char *od_name; + u_long od_base; + u_long od_size; + u_int od_irqs[5]; + struct resource_list od_resources; +}; + +static struct obio_device obio_devices[] = { + { "icu", PXA2X0_INTCTL_BASE, PXA2X0_INTCTL_SIZE, { 0 } }, + { "timer", PXA2X0_OST_BASE, PXA2X0_OST_SIZE, { PXA2X0_INT_OST0, PXA2X0_INT_OST1, PXA2X0_INT_OST2, PXA2X0_INT_OST3, 0 } }, + { "dmac", PXA2X0_DMAC_BASE, PXA2X0_DMAC_SIZE, { PXA2X0_INT_DMA, 0 } }, + { "gpio", PXA2X0_GPIO_BASE, PXA250_GPIO_SIZE, { PXA2X0_INT_GPIO0, PXA2X0_INT_GPIO1, PXA2X0_INT_GPION, 0 } }, + { "uart", PXA2X0_FFUART_BASE, PXA2X0_FFUART_SIZE, { PXA2X0_INT_FFUART, 0 } }, + { "uart", PXA2X0_BTUART_BASE, PXA2X0_BTUART_SIZE, { PXA2X0_INT_BTUART, 0 } }, + { "uart", PXA2X0_STUART_BASE, PXA2X0_STUART_SIZE, { PXA2X0_INT_STUART, 0 } }, + { "uart", PXA2X0_HWUART_BASE, PXA2X0_HWUART_SIZE, { PXA2X0_INT_HWUART, 0 } }, + { "smi", PXA2X0_CS0_START, PXA2X0_CS_SIZE * 6, { 0 } }, + { NULL, 0, 0, { 0 } } +}; + +void +pxa_identify(driver_t *driver, device_t parent) +{ + + BUS_ADD_CHILD(parent, 0, "pxa", 0); +} + +int +pxa_probe(device_t dev) +{ + + device_set_desc(dev, "XScale PXA On-board IO"); + return (BUS_PROBE_NOWILDCARD); +} + +int +pxa_attach(device_t dev) +{ + struct obio_softc *sc; + struct obio_device *od; + int i; + device_t child; + + sc = device_get_softc(dev); + + sc->obio_bst = obio_tag; + + sc->obio_mem.rm_type = RMAN_ARRAY; + sc->obio_mem.rm_descr = "PXA2X0 OBIO Memory"; + if (rman_init(&sc->obio_mem) != 0) + panic("pxa_attach: failed to init obio mem rman"); + if (rman_manage_region(&sc->obio_mem, 0, PXA250_PERIPH_END) != 0) + panic("pxa_attach: failed to set up obio mem rman"); + + sc->obio_irq.rm_type = RMAN_ARRAY; + sc->obio_irq.rm_descr = "PXA2X0 OBIO IRQ"; + if (rman_init(&sc->obio_irq) != 0) + panic("pxa_attach: failed to init obio irq rman"); + if (rman_manage_region(&sc->obio_irq, 0, 31) != 0) + panic("pxa_attach: failed to set up obio irq rman (main irqs)"); + if (rman_manage_region(&sc->obio_irq, IRQ_GPIO0, IRQ_GPIO_MAX) != 0) + panic("pxa_attach: failed to set up obio irq rman (gpio irqs)"); + + for (od = obio_devices; od->od_name != NULL; od++) { + resource_list_init(&od->od_resources); + + resource_list_add(&od->od_resources, SYS_RES_MEMORY, 0, + od->od_base, od->od_base + od->od_size, od->od_size); + + for (i = 0; od->od_irqs[i] != 0; i++) { + resource_list_add(&od->od_resources, SYS_RES_IRQ, i, + od->od_irqs[i], od->od_irqs[i], 1); + } + + child = device_add_child(dev, od->od_name, -1); + device_set_ivars(child, od); + } + + bus_generic_probe(dev); + bus_generic_attach(dev); + + return (0); +} + +static int +pxa_print_child(device_t dev, device_t child) +{ + struct obio_device *od; + int retval; + + od = (struct obio_device *)device_get_ivars(child); + if (od == NULL) + panic("Unknown device on pxa0"); + + retval = 0; + + retval += bus_print_child_header(dev, child); + + retval += resource_list_print_type(&od->od_resources, "at mem", + SYS_RES_MEMORY, "0x%08jx"); + retval += resource_list_print_type(&od->od_resources, "irq", + SYS_RES_IRQ, "%jd"); + + retval += bus_print_child_footer(dev, child); + + return (retval); +} + +static int +pxa_setup_intr(device_t dev, device_t child, struct resource *irq, int flags, + driver_filter_t *filter, driver_intr_t *ithread, void *arg, void **cookiep) +{ + struct obio_softc *sc; + int error; + + sc = (struct obio_softc *)device_get_softc(dev); + + error = BUS_SETUP_INTR(device_get_parent(dev), child, irq, flags, + filter, ithread, arg, cookiep); + if (error) + return (error); + return (0); +} + +static int +pxa_teardown_intr(device_t dev, device_t child, struct resource *ires, + void *cookie) +{ + return (BUS_TEARDOWN_INTR(device_get_parent(dev), child, ires, cookie));} + +static int +pxa_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) +{ + struct obio_device *od; + + od = (struct obio_device *)device_get_ivars(child); + + switch (which) { + case PXA_IVAR_BASE: + *((u_long *)result) = od->od_base; + break; + + default: + return (ENOENT); + } + + return (0); +} + +static struct resource_list * +pxa_get_resource_list(device_t dev, device_t child) +{ + struct obio_device *od; + + od = (struct obio_device *)device_get_ivars(child); + + if (od == NULL) + return (NULL); + + return (&od->od_resources); +} + +static struct resource * +pxa_alloc_resource(device_t dev, device_t child, int type, int *rid, + rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) +{ + struct obio_softc *sc; + struct obio_device *od; + struct resource *rv; + struct resource_list *rl; + struct resource_list_entry *rle; + struct rman *rm; + int needactivate; + + sc = (struct obio_softc *)device_get_softc(dev); + od = (struct obio_device *)device_get_ivars(child); + rl = &od->od_resources; + + rle = resource_list_find(rl, type, *rid); + if (rle == NULL) { + /* We can allocate GPIO-based IRQs lazily. */ + if (type == SYS_RES_IRQ) + return (pxa_alloc_gpio_irq(dev, child, type, rid, + start, end, count, flags)); + return (NULL); + } + if (rle->res != NULL) + panic("pxa_alloc_resource: resource is busy"); + + switch (type) { + case SYS_RES_IRQ: + rm = &sc->obio_irq; + break; + + case SYS_RES_MEMORY: + rm = &sc->obio_mem; + break; + + default: + return (NULL); + } + + needactivate = flags & RF_ACTIVE; + flags &= ~RF_ACTIVE; + rv = rman_reserve_resource(rm, rle->start, rle->end, rle->count, flags, + child); + if (rv == NULL) + return (NULL); + rle->res = rv; + rman_set_rid(rv, *rid); + if (type == SYS_RES_MEMORY) { + rman_set_bustag(rv, sc->obio_bst); + rman_set_bushandle(rv, rle->start); + } + + if (needactivate) { + if (bus_activate_resource(child, type, *rid, rv)) { + rman_release_resource(rv); + return (NULL); + } + } + + return (rv); +} + +static int +pxa_release_resource(device_t dev, device_t child, int type, int rid, + struct resource *r) +{ + struct obio_device *od; + struct resource_list *rl; + struct resource_list_entry *rle; + + od = (struct obio_device *)device_get_ivars(child); + rl = &od->od_resources; + + if (type == SYS_RES_IOPORT) + type = SYS_RES_MEMORY; + + rle = resource_list_find(rl, type, rid); + + if (!rle) + panic("pxa_release_resource: can't find resource"); + if (!rle->res) + panic("pxa_release_resource: resource entry is not busy"); + + rman_release_resource(rle->res); + rle->res = NULL; + + return (0); +} + +static int +pxa_activate_resource(device_t dev, device_t child, int type, int rid, + struct resource *r) +{ + + return (rman_activate_resource(r)); +} + +static device_method_t pxa_methods[] = { + DEVMETHOD(device_identify, pxa_identify), + DEVMETHOD(device_probe, pxa_probe), + DEVMETHOD(device_attach, pxa_attach), + + DEVMETHOD(bus_print_child, pxa_print_child), + + DEVMETHOD(bus_read_ivar, pxa_read_ivar), + DEVMETHOD(bus_setup_intr, pxa_setup_intr), + DEVMETHOD(bus_teardown_intr, pxa_teardown_intr), + + DEVMETHOD(bus_get_resource_list, pxa_get_resource_list), + DEVMETHOD(bus_alloc_resource, pxa_alloc_resource), + DEVMETHOD(bus_release_resource, pxa_release_resource), + DEVMETHOD(bus_activate_resource, pxa_activate_resource), + + {0, 0} +}; + +static driver_t pxa_driver = { + "pxa", + pxa_methods, + sizeof(struct obio_softc), +}; + +static devclass_t pxa_devclass; + +DRIVER_MODULE(pxa, nexus, pxa_driver, pxa_devclass, 0, 0); + +static struct resource * +pxa_alloc_gpio_irq(device_t dev, device_t child, int type, int *rid, + rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) +{ + struct obio_softc *sc; + struct obio_device *od; + struct resource_list *rl; + struct resource_list_entry *rle; + struct resource *rv; + struct rman *rm; + int needactivate; + + sc = device_get_softc(dev); + od = device_get_ivars(child); + rl = &od->od_resources; + rm = &sc->obio_irq; + + needactivate = flags & RF_ACTIVE; + flags &= ~RF_ACTIVE; + rv = rman_reserve_resource(rm, start, end, count, flags, child); + if (rv == NULL) + return (NULL); + + resource_list_add(rl, type, *rid, start, end, count); + rle = resource_list_find(rl, type, *rid); + if (rle == NULL) + panic("pxa_alloc_gpio_irq: unexpectedly can't find resource"); + + rle->res = rv; + rle->start = rman_get_start(rv); + rle->end = rman_get_end(rv); + rle->count = count; + + if (needactivate) { + if (bus_activate_resource(child, type, *rid, rv)) { + rman_release_resource(rv); + return (NULL); + } + } + + if (bootverbose) + device_printf(dev, "lazy allocation of irq %jd for %s\n", + start, device_get_nameunit(child)); + + return (rv); +} diff --git a/sys/arm/xscale/pxa/pxa_smi.c b/sys/arm/xscale/pxa/pxa_smi.c new file mode 100644 index 000000000000..569405e664d8 --- /dev/null +++ b/sys/arm/xscale/pxa/pxa_smi.c @@ -0,0 +1,356 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2006 Benno Rice. 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 ``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 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 + +static MALLOC_DEFINE(M_PXASMI, "PXA SMI", + "Data for static memory interface devices."); + +struct pxa_smi_softc { + struct resource *ps_res[1]; + struct rman ps_mem; + bus_space_tag_t ps_bst; + bus_addr_t ps_base; +}; + +struct smi_ivars { + struct resource_list smid_resources; + bus_addr_t smid_mem; +}; + +static struct resource_spec pxa_smi_spec[] = { + { SYS_RES_MEMORY, 0, RF_ACTIVE }, + { -1, 0 } +}; + +static int pxa_smi_probe(device_t); +static int pxa_smi_attach(device_t); + +static int pxa_smi_print_child(device_t, device_t); + +static int pxa_smi_read_ivar(device_t, device_t, int, uintptr_t *); + +static struct resource * pxa_smi_alloc_resource(device_t, device_t, + int, int *, rman_res_t, rman_res_t, rman_res_t, u_int); +static int pxa_smi_release_resource(device_t, device_t, + int, int, struct resource *); +static int pxa_smi_activate_resource(device_t, device_t, + int, int, struct resource *); + +static void pxa_smi_add_device(device_t, const char *, int); + +static int +pxa_smi_probe(device_t dev) +{ + + if (resource_disabled("smi", device_get_unit(dev))) + return (ENXIO); + + device_set_desc(dev, "Static Memory Interface"); + return (0); +} + +static int +pxa_smi_attach(device_t dev) +{ + int error, i, dunit; + const char *dname; + struct pxa_smi_softc *sc; + + sc = (struct pxa_smi_softc *)device_get_softc(dev); + + error = bus_alloc_resources(dev, pxa_smi_spec, sc->ps_res); + if (error) { + device_printf(dev, "could not allocate resources\n"); + return (ENXIO); + } + + sc->ps_mem.rm_type = RMAN_ARRAY; + sc->ps_mem.rm_descr = device_get_nameunit(dev); + if (rman_init(&sc->ps_mem) != 0) + panic("pxa_smi_attach: failed to init mem rman"); + if (rman_manage_region(&sc->ps_mem, 0, PXA2X0_CS_SIZE * 6) != 0) + panic("pxa_smi_attach: failed ot set up mem rman"); + + sc->ps_bst = base_tag; + sc->ps_base = rman_get_start(sc->ps_res[0]); + + i = 0; + while (resource_find_match(&i, &dname, &dunit, "at", + device_get_nameunit(dev)) == 0) { + pxa_smi_add_device(dev, dname, dunit); + } + + bus_generic_probe(dev); + bus_generic_attach(dev); + + return (0); +} + +static int +pxa_smi_print_child(device_t dev, device_t child) +{ + struct smi_ivars *smid; + int retval; + + smid = (struct smi_ivars *)device_get_ivars(child); + if (smid == NULL) { + device_printf(dev, "unknown device: %s\n", + device_get_nameunit(child)); + return (0); + } + + retval = 0; + + retval += bus_print_child_header(dev, child); + + retval += resource_list_print_type(&smid->smid_resources, "at mem", + SYS_RES_MEMORY, "%#jx"); + retval += resource_list_print_type(&smid->smid_resources, "irq", + SYS_RES_IRQ, "%jd"); + + retval += bus_print_child_footer(dev, child); + + return (retval); +} + +static int +pxa_smi_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) +{ + struct pxa_smi_softc *sc; + struct smi_ivars *smid; + + sc = device_get_softc(dev); + smid = device_get_ivars(child); + + switch (which) { + case SMI_IVAR_PHYSBASE: + *((bus_addr_t *)result) = smid->smid_mem; + break; + + default: + return (ENOENT); + } + + return (0); +} + +static struct resource * +pxa_smi_alloc_resource(device_t dev, device_t child, int type, int *rid, + rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) +{ + struct pxa_smi_softc *sc; + struct smi_ivars *smid; + struct resource *rv; + struct resource_list *rl; + struct resource_list_entry *rle; + int needactivate; + + sc = (struct pxa_smi_softc *)device_get_softc(dev); + smid = (struct smi_ivars *)device_get_ivars(child); + rl = &smid->smid_resources; + + if (type == SYS_RES_IOPORT) + type = SYS_RES_MEMORY; + + rle = resource_list_find(rl, type, *rid); + if (rle == NULL) + return (NULL); + if (rle->res != NULL) + panic("pxa_smi_alloc_resource: resource is busy"); + + needactivate = flags & RF_ACTIVE; + flags &= ~RF_ACTIVE; + + switch (type) { + case SYS_RES_MEMORY: + rv = rman_reserve_resource(&sc->ps_mem, rle->start, rle->end, + rle->count, flags, child); + if (rv == NULL) + return (NULL); + rle->res = rv; + rman_set_rid(rv, *rid); + rman_set_bustag(rv, sc->ps_bst); + rman_set_bushandle(rv, rle->start); + if (needactivate) { + if (bus_activate_resource(child, type, *rid, rv) != 0) { + rman_release_resource(rv); + return (NULL); + } + } + + break; + + case SYS_RES_IRQ: + rv = bus_alloc_resource(dev, type, rid, rle->start, rle->end, + rle->count, flags); + if (rv == NULL) + return (NULL); + if (needactivate) { + if (bus_activate_resource(child, type, *rid, rv) != 0) { + bus_release_resource(dev, type, *rid, rv); + return (NULL); + } + } + + break; + + default: + return (NULL); + } + + return (rv); +} + +static int +pxa_smi_release_resource(device_t dev, device_t child, int type, int rid, + struct resource *r) +{ + struct smi_ivars *smid; + struct resource_list *rl; + struct resource_list_entry *rle; + + if (type == SYS_RES_IRQ) + return (bus_release_resource(dev, SYS_RES_IRQ, rid, r)); + + smid = (struct smi_ivars *)device_get_ivars(child); + rl = &smid->smid_resources; + + if (type == SYS_RES_IOPORT) + type = SYS_RES_MEMORY; + + rle = resource_list_find(rl, type, rid); + if (rle == NULL) + panic("pxa_smi_release_resource: can't find resource"); + if (rle->res == NULL) + panic("pxa_smi_release_resource: resource entry not busy"); + + rman_release_resource(rle->res); + rle->res = NULL; + + return (0); +} + +static int +pxa_smi_activate_resource(device_t dev, device_t child, int type, int rid, + struct resource *r) +{ + struct pxa_smi_softc *sc; + + sc = (struct pxa_smi_softc *)device_get_softc(dev); + + if (type == SYS_RES_IRQ) + return (bus_activate_resource(dev, SYS_RES_IRQ, rid, r)); + + rman_set_bushandle(r, (bus_space_handle_t)pmap_mapdev(rman_get_start(r), + rman_get_size(r))); + return (rman_activate_resource(r)); +} + +static device_method_t pxa_smi_methods[] = { + DEVMETHOD(device_probe, pxa_smi_probe), + DEVMETHOD(device_attach, pxa_smi_attach), + + DEVMETHOD(bus_print_child, pxa_smi_print_child), + + DEVMETHOD(bus_read_ivar, pxa_smi_read_ivar), + + DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), + + DEVMETHOD(bus_alloc_resource, pxa_smi_alloc_resource), + DEVMETHOD(bus_release_resource, pxa_smi_release_resource), + DEVMETHOD(bus_activate_resource, pxa_smi_activate_resource), + + {0, 0} +}; + +static driver_t pxa_smi_driver = { + "smi", + pxa_smi_methods, + sizeof(struct pxa_smi_softc), +}; + +static devclass_t pxa_smi_devclass; + +DRIVER_MODULE(smi, pxa, pxa_smi_driver, pxa_smi_devclass, 0, 0); + +static void +pxa_smi_add_device(device_t dev, const char *name, int unit) +{ + device_t child; + int start, count; + struct smi_ivars *ivars; + + ivars = (struct smi_ivars *)malloc( + sizeof(struct smi_ivars), M_PXASMI, M_WAITOK); + + child = device_add_child(dev, name, unit); + if (child == NULL) { + free(ivars, M_PXASMI); + return; + } + + device_set_ivars(child, ivars); + resource_list_init(&ivars->smid_resources); + + start = 0; + count = 0; + resource_int_value(name, unit, "mem", &start); + resource_int_value(name, unit, "size", &count); + if (start > 0 || count > 0) { + resource_list_add(&ivars->smid_resources, SYS_RES_MEMORY, 0, + start, start + count, count); + ivars->smid_mem = (bus_addr_t)start; + } + + start = -1; + count = 0; + resource_int_value(name, unit, "irq", &start); + if (start > -1) + resource_list_add(&ivars->smid_resources, SYS_RES_IRQ, 0, start, + start, 1); + + if (resource_disabled(name, unit)) + device_disable(child); +} diff --git a/sys/arm/xscale/pxa/pxa_space.c b/sys/arm/xscale/pxa/pxa_space.c new file mode 100644 index 000000000000..bb235c935b29 --- /dev/null +++ b/sys/arm/xscale/pxa/pxa_space.c @@ -0,0 +1,267 @@ +/* $NetBSD: obio_space.c,v 1.6 2003/07/15 00:25:05 lukem Exp $ */ + +/*- + * SPDX-License-Identifier: BSD-4-Clause + * + * 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 PXA devices + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include + +#include + +#include +#include + +static MALLOC_DEFINE(M_PXATAG, "PXA bus_space tags", "Bus_space tags for PXA"); + +/* Prototypes for all the bus_space structure functions */ +bs_protos(generic); +bs_protos(pxa); + +/* + * The obio bus space tag. This is constant for all instances, so + * we never have to explicitly "create" it. + */ +struct bus_space _base_tag = { + /* cookie */ + .bs_privdata = NULL, + + /* 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 = pxa_bs_r_1, + .bs_r_2 = pxa_bs_r_2, + .bs_r_4 = pxa_bs_r_4, + .bs_r_8 = BS_UNIMPLEMENTED, + + /* read multiple */ + .bs_rm_1 = pxa_bs_rm_1, + .bs_rm_2 = pxa_bs_rm_2, + .bs_rm_4 = BS_UNIMPLEMENTED, + .bs_rm_8 = BS_UNIMPLEMENTED, + + /* read region */ + .bs_rr_1 = pxa_bs_rr_1, + .bs_rr_2 = BS_UNIMPLEMENTED, + .bs_rr_4 = BS_UNIMPLEMENTED, + .bs_rr_8 = BS_UNIMPLEMENTED, + + /* write (single) */ + .bs_w_1 = pxa_bs_w_1, + .bs_w_2 = pxa_bs_w_2, + .bs_w_4 = pxa_bs_w_4, + .bs_w_8 = BS_UNIMPLEMENTED, + + /* write multiple */ + .bs_wm_1 = pxa_bs_wm_1, + .bs_wm_2 = pxa_bs_wm_2, + .bs_wm_4 = BS_UNIMPLEMENTED, + .bs_wm_8 = BS_UNIMPLEMENTED, + + /* write region */ + .bs_wr_1 = BS_UNIMPLEMENTED, + .bs_wr_2 = BS_UNIMPLEMENTED, + .bs_wr_4 = BS_UNIMPLEMENTED, + .bs_wr_8 = BS_UNIMPLEMENTED, + + /* set multiple */ + .bs_sm_1 = BS_UNIMPLEMENTED, + .bs_sm_2 = BS_UNIMPLEMENTED, + .bs_sm_4 = BS_UNIMPLEMENTED, + .bs_sm_8 = BS_UNIMPLEMENTED, + + /* set region */ + .bs_sr_1 = BS_UNIMPLEMENTED, + .bs_sr_2 = BS_UNIMPLEMENTED, + .bs_sr_4 = BS_UNIMPLEMENTED, + .bs_sr_8 = BS_UNIMPLEMENTED, + + /* copy */ + .bs_c_1 = BS_UNIMPLEMENTED, + .bs_c_2 = BS_UNIMPLEMENTED, + .bs_c_4 = BS_UNIMPLEMENTED, + .bs_c_8 = BS_UNIMPLEMENTED, + + /* read stream (single) */ + .bs_r_1_s = BS_UNIMPLEMENTED, + .bs_r_2_s = BS_UNIMPLEMENTED, + .bs_r_4_s = BS_UNIMPLEMENTED, + .bs_r_8_s = BS_UNIMPLEMENTED, + + /* read multiple stream */ + .bs_rm_1_s = BS_UNIMPLEMENTED, + .bs_rm_2_s = BS_UNIMPLEMENTED, + .bs_rm_4_s = BS_UNIMPLEMENTED, + .bs_rm_8_s = BS_UNIMPLEMENTED, + + /* read region stream */ + .bs_rr_1_s = BS_UNIMPLEMENTED, + .bs_rr_2_s = BS_UNIMPLEMENTED, + .bs_rr_4_s = BS_UNIMPLEMENTED, + .bs_rr_8_s = BS_UNIMPLEMENTED, + + /* write stream (single) */ + .bs_w_1_s = BS_UNIMPLEMENTED, + .bs_w_2_s = BS_UNIMPLEMENTED, + .bs_w_4_s = BS_UNIMPLEMENTED, + .bs_w_8_s = BS_UNIMPLEMENTED, + + /* write multiple stream */ + .bs_wm_1_s = BS_UNIMPLEMENTED, + .bs_wm_2_s = BS_UNIMPLEMENTED, + .bs_wm_4_s = BS_UNIMPLEMENTED, + .bs_wm_8_s = BS_UNIMPLEMENTED, + + /* write region stream */ + .bs_wr_1_s = BS_UNIMPLEMENTED, + .bs_wr_2_s = BS_UNIMPLEMENTED, + .bs_wr_4_s = BS_UNIMPLEMENTED, + .bs_wr_8_s = BS_UNIMPLEMENTED, +}; + +static struct bus_space _obio_tag; + +bus_space_tag_t base_tag = &_base_tag; +bus_space_tag_t obio_tag = NULL; + +void +pxa_obio_tag_init(void) +{ + + bcopy(&_base_tag, &_obio_tag, sizeof(struct bus_space)); + _obio_tag.bs_privdata = (void *)PXA2X0_PERIPH_OFFSET; + obio_tag = &_obio_tag; +} + +bus_space_tag_t +pxa_bus_tag_alloc(bus_addr_t offset) +{ + struct bus_space *tag; + + tag = (struct bus_space *)malloc(sizeof(struct bus_space), M_PXATAG, + M_WAITOK); + + bcopy(&_base_tag, tag, sizeof(struct bus_space)); + tag->bs_privdata = (void *)offset; + + return ((bus_space_tag_t)tag); +} + + +#define READ_SINGLE(type, proto, base) \ + type \ + proto(bus_space_tag_t tag, bus_space_handle_t bsh, bus_size_t offset) \ + { \ + bus_addr_t tag_offset; \ + type value; \ + tag_offset = (bus_addr_t)tag->bs_privdata; \ + value = base(NULL, bsh + tag_offset, offset); \ + return (value); \ + } + +READ_SINGLE(u_int8_t, pxa_bs_r_1, generic_bs_r_1) +READ_SINGLE(u_int16_t, pxa_bs_r_2, generic_bs_r_2) +READ_SINGLE(u_int32_t, pxa_bs_r_4, generic_bs_r_4) + +#undef READ_SINGLE + +#define WRITE_SINGLE(type, proto, base) \ + void \ + proto(bus_space_tag_t tag, bus_space_handle_t bsh, bus_size_t offset, \ + type value) \ + { \ + bus_addr_t tag_offset; \ + tag_offset = (bus_addr_t)tag->bs_privdata; \ + base(NULL, bsh + tag_offset, offset, value); \ + } + +WRITE_SINGLE(u_int8_t, pxa_bs_w_1, generic_bs_w_1) +WRITE_SINGLE(u_int16_t, pxa_bs_w_2, generic_bs_w_2) +WRITE_SINGLE(u_int32_t, pxa_bs_w_4, generic_bs_w_4) + +#undef WRITE_SINGLE + +#define READ_MULTI(type, proto, base) \ + void \ + proto(bus_space_tag_t tag, bus_space_handle_t bsh, bus_size_t offset, \ + type *dest, bus_size_t count) \ + { \ + bus_addr_t tag_offset; \ + tag_offset = (bus_addr_t)tag->bs_privdata; \ + base(NULL, bsh + tag_offset, offset, dest, count); \ + } + +READ_MULTI(u_int8_t, pxa_bs_rm_1, generic_bs_rm_1) +READ_MULTI(u_int16_t, pxa_bs_rm_2, generic_bs_rm_2) + +READ_MULTI(u_int8_t, pxa_bs_rr_1, generic_bs_rr_1) + +#undef READ_MULTI + +#define WRITE_MULTI(type, proto, base) \ + void \ + proto(bus_space_tag_t tag, bus_space_handle_t bsh, bus_size_t offset, \ + const type *src, bus_size_t count) \ + { \ + bus_addr_t tag_offset; \ + tag_offset = (bus_addr_t)tag->bs_privdata; \ + base(NULL, bsh + tag_offset, offset, src, count); \ + } + +WRITE_MULTI(u_int8_t, pxa_bs_wm_1, generic_bs_wm_1) +WRITE_MULTI(u_int16_t, pxa_bs_wm_2, generic_bs_wm_2) + +#undef WRITE_MULTI diff --git a/sys/arm/xscale/pxa/pxa_timer.c b/sys/arm/xscale/pxa/pxa_timer.c new file mode 100644 index 000000000000..b000f0271d96 --- /dev/null +++ b/sys/arm/xscale/pxa/pxa_timer.c @@ -0,0 +1,322 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2006 Benno Rice. 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 ``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 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 + +#define PXA_TIMER_FREQUENCY 3686400 +#define PXA_TIMER_TICK (PXA_TIMER_FREQUENCY / hz) + +struct pxa_timer_softc { + struct resource * pt_res[5]; + bus_space_tag_t pt_bst; + bus_space_handle_t pt_bsh; +}; + +static struct resource_spec pxa_timer_spec[] = { + { SYS_RES_MEMORY, 0, RF_ACTIVE }, + { SYS_RES_IRQ, 0, RF_ACTIVE }, + { SYS_RES_IRQ, 1, RF_ACTIVE }, + { SYS_RES_IRQ, 2, RF_ACTIVE }, + { SYS_RES_IRQ, 3, RF_ACTIVE }, + { -1, 0 } +}; + +static struct pxa_timer_softc *timer_softc = NULL; + +static int pxa_timer_probe(device_t); +static int pxa_timer_attach(device_t); + +static driver_filter_t pxa_hardclock; + +static unsigned pxa_timer_get_timecount(struct timecounter *); + +uint32_t pxa_timer_get_osmr(int); +void pxa_timer_set_osmr(int, uint32_t); +uint32_t pxa_timer_get_oscr(void); +void pxa_timer_set_oscr(uint32_t); +uint32_t pxa_timer_get_ossr(void); +void pxa_timer_clear_ossr(uint32_t); +void pxa_timer_watchdog_enable(void); +void pxa_timer_watchdog_disable(void); +void pxa_timer_interrupt_enable(int); +void pxa_timer_interrupt_disable(int); + +static struct timecounter pxa_timer_timecounter = { + .tc_get_timecount = pxa_timer_get_timecount, + .tc_name = "OS Timer", + .tc_frequency = PXA_TIMER_FREQUENCY, + .tc_counter_mask = ~0u, + .tc_quality = 1000, +}; + +static int +pxa_timer_probe(device_t dev) +{ + + device_set_desc(dev, "OS Timer"); + return (0); +} + +static int +pxa_timer_attach(device_t dev) +{ + int error; + void *ihl; + struct pxa_timer_softc *sc; + + sc = (struct pxa_timer_softc *)device_get_softc(dev); + + if (timer_softc != NULL) + return (ENXIO); + + error = bus_alloc_resources(dev, pxa_timer_spec, sc->pt_res); + if (error) { + device_printf(dev, "could not allocate resources\n"); + return (ENXIO); + } + + sc->pt_bst = rman_get_bustag(sc->pt_res[0]); + sc->pt_bsh = rman_get_bushandle(sc->pt_res[0]); + + timer_softc = sc; + + pxa_timer_interrupt_disable(-1); + pxa_timer_watchdog_disable(); + + if (bus_setup_intr(dev, sc->pt_res[1], INTR_TYPE_CLK, + pxa_hardclock, NULL, NULL, &ihl) != 0) { + bus_release_resources(dev, pxa_timer_spec, sc->pt_res); + device_printf(dev, "could not setup hardclock interrupt\n"); + return (ENXIO); + } + + return (0); +} + +static int +pxa_hardclock(void *arg) +{ + struct trapframe *frame; + + frame = (struct trapframe *)arg; + + /* Clear the interrupt */ + pxa_timer_clear_ossr(OST_SR_CH0); + + /* Schedule next tick */ + pxa_timer_set_osmr(0, pxa_timer_get_oscr() + PXA_TIMER_TICK); + + /* Do what we came here for */ + hardclock(TRAPF_USERMODE(frame), TRAPF_PC(frame)); + + return (FILTER_HANDLED); +} + +static device_method_t pxa_timer_methods[] = { + DEVMETHOD(device_probe, pxa_timer_probe), + DEVMETHOD(device_attach, pxa_timer_attach), + + {0, 0} +}; + +static driver_t pxa_timer_driver = { + "timer", + pxa_timer_methods, + sizeof(struct pxa_timer_softc), +}; + +static devclass_t pxa_timer_devclass; + +DRIVER_MODULE(pxatimer, pxa, pxa_timer_driver, pxa_timer_devclass, 0, 0); + +static unsigned +pxa_timer_get_timecount(struct timecounter *tc) +{ + + return (pxa_timer_get_oscr()); +} + +void +cpu_initclocks(void) +{ + + pxa_timer_set_oscr(0); + pxa_timer_set_osmr(0, PXA_TIMER_TICK); + pxa_timer_interrupt_enable(0); + + tc_init(&pxa_timer_timecounter); +} + +void +cpu_reset(void) +{ + uint32_t val; + + (void)disable_interrupts(PSR_I|PSR_F); + + val = pxa_timer_get_oscr(); + val += PXA_TIMER_FREQUENCY; + pxa_timer_set_osmr(3, val); + pxa_timer_watchdog_enable(); + + for(;;); +} + +void +DELAY(int usec) +{ + uint32_t val; + + if (timer_softc == NULL) { + for (; usec > 0; usec--) + for (val = 100; val > 0; val--) + ; + return; + } + TSENTER(); + + val = pxa_timer_get_oscr(); + val += (PXA_TIMER_FREQUENCY * usec) / 1000000; + while (pxa_timer_get_oscr() <= val); + TSEXIT(); +} + +uint32_t +pxa_timer_get_osmr(int which) +{ + + return (bus_space_read_4(timer_softc->pt_bst, + timer_softc->pt_bsh, which * 0x4)); +} + +void +pxa_timer_set_osmr(int which, uint32_t val) +{ + + bus_space_write_4(timer_softc->pt_bst, + timer_softc->pt_bsh, which * 0x4, val); +} + +uint32_t +pxa_timer_get_oscr(void) +{ + + return (bus_space_read_4(timer_softc->pt_bst, + timer_softc->pt_bsh, OST_CR)); +} + +void +pxa_timer_set_oscr(uint32_t val) +{ + + bus_space_write_4(timer_softc->pt_bst, + timer_softc->pt_bsh, OST_CR, val); +} + +uint32_t +pxa_timer_get_ossr(void) +{ + + return (bus_space_read_4(timer_softc->pt_bst, + timer_softc->pt_bsh, OST_SR)); +} + +void +pxa_timer_clear_ossr(uint32_t val) +{ + + bus_space_write_4(timer_softc->pt_bst, + timer_softc->pt_bsh, OST_SR, val); +} + +void +pxa_timer_watchdog_enable(void) +{ + + bus_space_write_4(timer_softc->pt_bst, + timer_softc->pt_bsh, OST_WR, 0x1); +} + +void +pxa_timer_watchdog_disable(void) +{ + + bus_space_write_4(timer_softc->pt_bst, + timer_softc->pt_bsh, OST_WR, 0x0); +} + +void +pxa_timer_interrupt_enable(int which) +{ + uint32_t oier; + + if (which == -1) { + bus_space_write_4(timer_softc->pt_bst, + timer_softc->pt_bsh, OST_IR, 0xf); + return; + } + + oier = bus_space_read_4(timer_softc->pt_bst, + timer_softc->pt_bsh, OST_IR); + oier |= 1 << which; + bus_space_write_4(timer_softc->pt_bst, + timer_softc->pt_bsh, OST_IR, oier); +} + +void +pxa_timer_interrupt_disable(int which) +{ + uint32_t oier; + + if (which == -1) { + bus_space_write_4(timer_softc->pt_bst, + timer_softc->pt_bsh, OST_IR, 0); + } + + oier = bus_space_read_4(timer_softc->pt_bst, + timer_softc->pt_bsh, OST_IR); + oier &= ~(1 << which); + bus_space_write_4(timer_softc->pt_bst, + timer_softc->pt_bsh, OST_IR, oier); +} diff --git a/sys/arm/xscale/pxa/pxareg.h b/sys/arm/xscale/pxa/pxareg.h new file mode 100644 index 000000000000..eb1f53b2790b --- /dev/null +++ b/sys/arm/xscale/pxa/pxareg.h @@ -0,0 +1,758 @@ +/* $NetBSD: pxa2x0reg.h,v 1.9 2006/04/10 04:13:58 simonb Exp $ */ + +/*- + * SPDX-License-Identifier: BSD-4-Clause + * + * Copyright (c) 2002 Genetec Corporation. All rights reserved. + * Written by Hiroyuki Bessho for Genetec Corporation. + * + * 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 + * Genetec Corporation. + * 4. The name of Genetec Corporation may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY GENETEC CORPORATION ``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 GENETEC CORPORATION + * 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. + * + * $FreeBSD$ + */ + + +/* + * Intel PXA2[15]0 processor is XScale based integrated CPU + * + * Reference: + * Intel(r) PXA250 and PXA210 Application Processors + * Developer's Manual + * (278522-001.pdf) + */ +#ifndef _ARM_XSCALE_PXAREG_H_ +#define _ARM_XSCALE_PXAREG_H_ + +#ifndef _LOCORE +#include /* for uint32_t */ +#endif + +/* + * Chip select domains + */ +#define PXA2X0_CS0_START 0x00000000 +#define PXA2X0_CS1_START 0x04000000 +#define PXA2X0_CS2_START 0x08000000 +#define PXA2X0_CS3_START 0x0c000000 +#define PXA2X0_CS4_START 0x10000000 +#define PXA2X0_CS5_START 0x14000000 +#define PXA2X0_CS_SIZE 0x04000000 + +#define PXA2X0_PCMCIA_SLOT0 0x20000000 +#define PXA2X0_PCMCIA_SLOT1 0x30000000 + +#define PXA2X0_PERIPH_START 0x40000000 +/* #define PXA2X0_MEMCTL_START 0x48000000 */ +#define PXA270_PERIPH_END 0x530fffff +#define PXA250_PERIPH_END 0x480fffff +#define PXA2X0_PERIPH_OFFSET 0xa8000000 + +#define PXA2X0_SDRAM0_START 0xa0000000 +#define PXA2X0_SDRAM1_START 0xa4000000 +#define PXA2X0_SDRAM2_START 0xa8000000 +#define PXA2X0_SDRAM3_START 0xac000000 +#define PXA2X0_SDRAM_BANKS 4 +#define PXA2X0_SDRAM_BANK_SIZE 0x04000000 + +/* + * Physical address of integrated peripherals + */ + +#define PXA2X0_DMAC_BASE 0x40000000 +#define PXA2X0_DMAC_SIZE 0x300 +#define PXA2X0_FFUART_BASE 0x40100000 /* Full Function UART */ +#define PXA2X0_FFUART_SIZE 0x20 +#define PXA2X0_BTUART_BASE 0x40200000 /* Bluetooth UART */ +#define PXA2X0_BTUART_SIZE 0x24 +#define PXA2X0_I2C_BASE 0x40300000 +#define PXA2X0_I2C_SIZE 0x000016a4 +#define PXA2X0_I2S_BASE 0x40400000 +#define PXA2X0_AC97_BASE 0x40500000 +#define PXA2X0_AC97_SIZE 0x600 +#define PXA2X0_USBDC_BASE 0x40600000 /* USB Client */ +#define PXA2X0_USBDC_SIZE 0x0e04 +#define PXA2X0_STUART_BASE 0x40700000 /* Standard UART */ +#define PXA2X0_STUART_SIZE 0x24 +#define PXA2X0_ICP_BASE 0x40800000 +#define PXA2X0_RTC_BASE 0x40900000 +#define PXA2X0_RTC_SIZE 0x10 +#define PXA2X0_OST_BASE 0x40a00000 /* OS Timer */ +#define PXA2X0_OST_SIZE 0x20 +#define PXA2X0_PWM0_BASE 0x40b00000 +#define PXA2X0_PWM1_BASE 0x40c00000 +#define PXA2X0_INTCTL_BASE 0x40d00000 /* Interrupt controller */ +#define PXA2X0_INTCTL_SIZE 0x20 +#define PXA2X0_GPIO_BASE 0x40e00000 + +#define PXA270_GPIO_SIZE 0x150 +#define PXA250_GPIO_SIZE 0x70 +#define PXA2X0_POWMAN_BASE 0x40f00000 /* Power management */ +#define PXA2X0_SSP_BASE 0x41000000 +#define PXA2X0_MMC_BASE 0x41100000 /* MultiMediaCard */ +#define PXA2X0_MMC_SIZE 0x48 +#define PXA2X0_CLKMAN_BASE 0x41300000 /* Clock Manager */ +#define PXA2X0_CLKMAN_SIZE 12 +#define PXA2X0_HWUART_BASE 0x41600000 /* Hardware UART */ +#define PXA2X0_HWUART_SIZE 0x30 +#define PXA2X0_LCDC_BASE 0x44000000 /* LCD Controller */ +#define PXA2X0_LCDC_SIZE 0x220 +#define PXA2X0_MEMCTL_BASE 0x48000000 /* Memory Controller */ +#define PXA2X0_MEMCTL_SIZE 0x48 +#define PXA2X0_USBH_BASE 0x4c000000 /* USB Host controller */ +#define PXA2X0_USBH_SIZE 0x70 + +/* Internal SRAM storage. PXA27x only */ +#define PXA270_SRAM0_START 0x5c000000 +#define PXA270_SRAM1_START 0x5c010000 +#define PXA270_SRAM2_START 0x5c020000 +#define PXA270_SRAM3_START 0x5c030000 +#define PXA270_SRAM_BANKS 4 +#define PXA270_SRAM_BANK_SIZE 0x00010000 + +/* width of interrupt controller */ +#define ICU_LEN 32 /* but [0..7,15,16] is not used */ +#define ICU_INT_HWMASK 0xffffff00 +#define PXA250_IRQ_MIN 8 /* 0..7 are not used by integrated + peripherals */ +#define PXA270_IRQ_MIN 0 + +#define PXA2X0_INT_USBH1 3 /* USB host (OHCI) */ + +#define PXA2X0_INT_HWUART 7 +#define PXA2X0_INT_GPIO0 8 +#define PXA2X0_INT_GPIO1 9 +#define PXA2X0_INT_GPION 10 /* irq from GPIO[2..80] */ +#define PXA2X0_INT_USB 11 +#define PXA2X0_INT_PMU 12 +#define PXA2X0_INT_I2S 13 +#define PXA2X0_INT_AC97 14 +#define PXA2X0_INT_LCD 17 +#define PXA2X0_INT_I2C 18 +#define PXA2X0_INT_ICP 19 +#define PXA2X0_INT_STUART 20 +#define PXA2X0_INT_BTUART 21 +#define PXA2X0_INT_FFUART 22 +#define PXA2X0_INT_MMC 23 +#define PXA2X0_INT_SSP 24 +#define PXA2X0_INT_DMA 25 +#define PXA2X0_INT_OST0 26 +#define PXA2X0_INT_OST1 27 +#define PXA2X0_INT_OST2 28 +#define PXA2X0_INT_OST3 29 +#define PXA2X0_INT_RTCHZ 30 +#define PXA2X0_INT_ALARM 31 /* RTC Alarm interrupt */ + +/* DMAC */ +#define DMAC_N_CHANNELS 16 +#define DMAC_N_PRIORITIES 3 + +#define DMAC_DCSR(n) ((n)*4) +#define DCSR_BUSERRINTR (1<<0) /* bus error interrupt */ +#define DCSR_STARTINTR (1<<1) /* start interrupt */ +#define DCSR_ENDINTR (1<<2) /* end interrupt */ +#define DCSR_STOPSTATE (1<<3) /* channel is not running */ +#define DCSR_REQPEND (1<<8) /* request pending */ +#define DCSR_STOPIRQEN (1<<29) /* stop interrupt enable */ +#define DCSR_NODESCFETCH (1<<30) /* no-descriptor fetch mode */ +#define DCSR_RUN (1<<31) +#define DMAC_DINT 0x00f0 /* DAM interrupt */ +#define DMAC_DINT_MASK 0xffffu +#define DMAC_DRCMR(n) (0x100+(n)*4) /* Channel map register */ +#define DRCMR_CHLNUM 0x0f /* channel number */ +#define DRCMR_MAPVLD (1<<7) /* map valid */ +#define DMAC_DDADR(n) (0x0200+(n)*16) +#define DDADR_STOP (1<<0) +#define DMAC_DSADR(n) (0x0204+(n)*16) +#define DMAC_DTADR(n) (0x0208+(n)*16) +#define DMAC_DCMD(n) (0x020c+(n)*16) +#define DCMD_LENGTH_MASK 0x1fff +#define DCMD_WIDTH_SHIFT 14 +#define DCMD_WIDTH_0 (0< + +struct obio_softc { + bus_space_tag_t obio_bst; /* bus space tag */ + struct rman obio_mem; + struct rman obio_irq; +}; + +extern bus_space_tag_t base_tag; +extern bus_space_tag_t obio_tag; +void pxa_obio_tag_init(void); +bus_space_tag_t pxa_bus_tag_alloc(bus_addr_t); + +uint32_t pxa_gpio_get_function(int); +uint32_t pxa_gpio_set_function(int, uint32_t); +int pxa_gpio_setup_intrhandler(const char *, driver_filter_t *, + driver_intr_t *, void *, int, int, void **); +void pxa_gpio_mask_irq(int); +void pxa_gpio_unmask_irq(int); +int pxa_gpio_get_next_irq(void); + +struct dmac_channel; + +struct dmac_descriptor { + uint32_t ddadr; + uint32_t dsadr; + uint32_t dtadr; + uint32_t dcmd; +}; +#define DMACD_SET_DESCRIPTOR(d, dadr) do { d->ddadr = dadr; } while (0) +#define DMACD_SET_SOURCE(d, sadr) do { d->dsadr = sadr; } while (0) +#define DMACD_SET_TARGET(d, tadr) do { d->dtadr = tadr; } while (0) +#define DMACD_SET_COMMAND(d, cmd) do { d->dcmd = cmd; } while (0) + +#define DMAC_PRIORITY_HIGHEST 1 +#define DMAC_PRIORITY_HIGH 2 +#define DMAC_PRIORITY_LOW 3 + +int pxa_dmac_alloc(int, struct dmac_channel **, int); +void pxa_dmac_release(struct dmac_channel *); +int pxa_dmac_transfer(struct dmac_channel *, bus_addr_t); +int pxa_dmac_transfer_single(struct dmac_channel *, + bus_addr_t, bus_addr_t, uint32_t); +int pxa_dmac_transfer_done(struct dmac_channel *); +int pxa_dmac_transfer_failed(struct dmac_channel *); + +enum pxa_device_ivars { + PXA_IVAR_BASE, +}; + +enum smi_device_ivars { + SMI_IVAR_PHYSBASE, +}; + +#define PXA_ACCESSOR(var, ivar, type) \ + __BUS_ACCESSOR(pxa, var, PXA, ivar, type) + +PXA_ACCESSOR(base, BASE, u_long) + +#undef PXA_ACCESSOR + +#define SMI_ACCESSOR(var, ivar, type) \ + __BUS_ACCESSOR(smi, var, SMI, ivar, type) + +SMI_ACCESSOR(physbase, PHYSBASE, bus_addr_t) + +#undef CSR_ACCESSOR + +#endif /* _PXAVAR_H_ */ diff --git a/sys/arm/xscale/pxa/std.pxa b/sys/arm/xscale/pxa/std.pxa new file mode 100644 index 000000000000..b8e3484802cb --- /dev/null +++ b/sys/arm/xscale/pxa/std.pxa @@ -0,0 +1,9 @@ +# XScale PXA generic configuration +# $FreeBSD$ +files "../xscale/pxa/files.pxa" +include "../xscale/std.xscale" +makeoptions KERNPHYSADDR=0xa0200000 +makeoptions KERNVIRTADDR=0xc0200000 +makeoptions CONF_CFLAGS=-mcpu=xscale +options XSCALE_CACHE_READ_WRITE_ALLOCATE +machine arm diff --git a/sys/arm/xscale/pxa/uart_bus_pxa.c b/sys/arm/xscale/pxa/uart_bus_pxa.c new file mode 100644 index 000000000000..ed3ae53b23c5 --- /dev/null +++ b/sys/arm/xscale/pxa/uart_bus_pxa.c @@ -0,0 +1,105 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2006 Benno Rice. 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 ``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 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" + +#define PXA_UART_UUE 0x40 /* UART Unit Enable */ + +static int uart_pxa_probe(device_t dev); + +static device_method_t uart_pxa_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, uart_pxa_probe), + DEVMETHOD(device_attach, uart_bus_attach), + DEVMETHOD(device_detach, uart_bus_detach), + { 0, 0 } +}; + +static driver_t uart_pxa_driver = { + uart_driver_name, + uart_pxa_methods, + sizeof(struct uart_softc), +}; + +static int +uart_pxa_probe(device_t dev) +{ + bus_space_handle_t base; + struct uart_softc *sc; + + base = (bus_space_handle_t)pxa_get_base(dev); +#ifdef QEMU_WORKAROUNDS + /* + * QEMU really exposes only the first uart unless + * you specify several of them in the configuration. + * Otherwise all the rest of UARTs stay unconnected, + * which causes problems in the ns16550 attach routine. + * Unfortunately, even if you provide qemu with 4 uarts + * on the command line, it has a bug where it segfaults + * trying to enable bluetooth on the HWUART. So we just + * allow the FFUART to be attached. + * Also, don't check the UUE (UART Unit Enable) bit, as + * the gumstix bootloader doesn't set it. + */ + if (base != PXA2X0_FFUART_BASE) + return (ENXIO); +#else + /* Check to see if the enable bit's on. */ + if ((bus_space_read_4(obio_tag, base, + (REG_IER << 2)) & PXA_UART_UUE) == 0) + return (ENXIO); +#endif + sc = device_get_softc(dev); + sc->sc_class = &uart_ns8250_class; + + return(uart_bus_probe(dev, 2, 0, PXA2X0_COM_FREQ, 0, 0)); +} + +DRIVER_MODULE(uart, pxa, uart_pxa_driver, uart_devclass, 0, 0); diff --git a/sys/arm/xscale/pxa/uart_cpu_pxa.c b/sys/arm/xscale/pxa/uart_cpu_pxa.c new file mode 100644 index 000000000000..68c253c32adb --- /dev/null +++ b/sys/arm/xscale/pxa/uart_cpu_pxa.c @@ -0,0 +1,71 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2003 Marcel Moolenaar + * 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 ``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 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; + +int +uart_cpu_eqres(struct uart_bas *b1, struct uart_bas *b2) +{ + + return (b1->bsh == b2->bsh ? 1 : 0); +} + +int +uart_cpu_getdev(int devtype, struct uart_devinfo *di) +{ + + di->ops = uart_getops(&uart_ns8250_class); + di->bas.chan = 0; + di->bas.bst = obio_tag; + di->bas.regshft = 2; + di->bas.rclk = PXA2X0_COM_FREQ; + di->baudrate = 115200; + di->databits = 8; + di->stopbits = 1; + di->parity = UART_PARITY_NONE; + uart_bus_space_mem = obio_tag; + uart_bus_space_io = NULL; + di->bas.bsh = PXA2X0_FFUART_BASE; + return (0); +} diff --git a/sys/arm/xscale/std.xscale b/sys/arm/xscale/std.xscale new file mode 100644 index 000000000000..b5266bd8d80d --- /dev/null +++ b/sys/arm/xscale/std.xscale @@ -0,0 +1,3 @@ +# $FreeBSD$ +options ARM_CACHE_LOCK_ENABLE +options NO_EVENTTIMERS diff --git a/sys/conf/Makefile.arm b/sys/conf/Makefile.arm index b72464298e7c..2f6138d737d3 100644 --- a/sys/conf/Makefile.arm +++ b/sys/conf/Makefile.arm @@ -73,8 +73,9 @@ SYSTEM_LD_TAIL +=;sed s/" + SIZEOF_HEADERS"// ldscript.$M\ rm ${FULLKERNEL}.noheader FILES_CPU_FUNC = \ - $S/$M/$M/cpufunc_asm_arm9.S $S/$M/$M/cpufunc_asm.S \ - $S/$M/$M/cpufunc_asm_armv5_ec.S \ + $S/$M/$M/cpufunc_asm_arm9.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_fa526.S $S/$M/$M/cpufunc_asm_sheeva.S .if ${MACHINE_ARCH:Marmv[67]*} == "" && defined(KERNPHYSADDR) diff --git a/sys/conf/files.arm b/sys/conf/files.arm index 40cc305b1452..303297177e81 100644 --- a/sys/conf/files.arm +++ b/sys/conf/files.arm @@ -32,12 +32,14 @@ arm/arm/cpufunc.c standard arm/arm/cpufunc_asm.S standard arm/arm/cpufunc_asm_arm9.S optional cpu_arm9 | cpu_arm9e arm/arm/cpufunc_asm_arm11x6.S optional cpu_arm1176 -arm/arm/cpufunc_asm_armv4.S optional cpu_arm9 | cpu_arm9e | cpu_fa526 +arm/arm/cpufunc_asm_armv4.S optional cpu_arm9 | cpu_arm9e | cpu_fa526 | cpu_xscale_pxa2x0 | cpu_xscale_81342 arm/arm/cpufunc_asm_armv5_ec.S optional cpu_arm9e arm/arm/cpufunc_asm_armv7.S optional cpu_cortexa | cpu_krait | cpu_mv_pj4b arm/arm/cpufunc_asm_fa526.S optional cpu_fa526 arm/arm/cpufunc_asm_pj4b.S optional cpu_mv_pj4b arm/arm/cpufunc_asm_sheeva.S optional cpu_arm9e +arm/arm/cpufunc_asm_xscale.S optional cpu_xscale_pxa2x0 | cpu_xscale_81342 +arm/arm/cpufunc_asm_xscale_c3.S optional cpu_xscale_81342 arm/arm/cpuinfo.c standard arm/arm/cpu_asm-v6.S optional armv7 | armv6 arm/arm/db_disasm.c optional ddb diff --git a/sys/conf/options.arm b/sys/conf/options.arm index b6abc04330fc..b8f9d2fabaf9 100644 --- a/sys/conf/options.arm +++ b/sys/conf/options.arm @@ -16,6 +16,8 @@ CPU_CORTEXA opt_global.h CPU_KRAIT opt_global.h CPU_FA526 opt_global.h CPU_MV_PJ4B opt_global.h +CPU_XSCALE_81342 opt_global.h +CPU_XSCALE_PXA2X0 opt_global.h SMP_ON_UP opt_global.h # Runtime detection of MP extensions DEV_GIC opt_global.h DEV_PMU opt_global.h @@ -64,6 +66,8 @@ SOC_OMAP4 opt_global.h SOC_ROCKCHIP_RK3188 opt_global.h SOC_TI_AM335X opt_global.h SOC_TEGRA2 opt_global.h +XSCALE_CACHE_READ_WRITE_ALLOCATE opt_global.h +XSACLE_DISABLE_CCNT opt_timer.h VERBOSE_INIT_ARM opt_global.h VM_MAXUSER_ADDRESS opt_global.h GFB_DEBUG opt_gfb.h diff --git a/sys/dev/hwpmc/hwpmc_xscale.h b/sys/dev/hwpmc/hwpmc_xscale.h new file mode 100644 index 000000000000..384586451adb --- /dev/null +++ b/sys/dev/hwpmc/hwpmc_xscale.h @@ -0,0 +1,72 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2009 Rui Paulo + * 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. + * + * $FreeBSD$ + */ + +#ifndef _DEV_HWPMC_XSCALE_H_ +#define _DEV_HWPMC_XSCALE_H_ + +#define XSCALE_PMC_CAPS (PMC_CAP_INTERRUPT | PMC_CAP_USER | \ + PMC_CAP_SYSTEM | PMC_CAP_EDGE | \ + PMC_CAP_THRESHOLD | PMC_CAP_READ | \ + PMC_CAP_WRITE | PMC_CAP_INVERT | \ + PMC_CAP_QUALIFIER) + + +#define XSCALE_PMNC_ENABLE 0x01 /* Enable all Counters */ +#define XSCALE_PMNC_PMNRESET 0x02 /* Performance Counter Reset */ +#define XSCALE_PMNC_CCNTRESET 0x04 /* Clock Counter Reset */ +#define XSCALE_PMNC_CCNTDIV 0x08 /* Clock Counter Divider */ + +#define XSCALE_INTEN_CCNT 0x01 /* Enable Clock Counter Int. */ +#define XSCALE_INTEN_PMN0 0x02 /* Enable PMN0 Interrupts */ +#define XSCALE_INTEN_PMN1 0x04 /* Enable PMN1 Interrupts */ +#define XSCALE_INTEN_PMN2 0x08 /* Enable PMN2 Interrupts */ +#define XSCALE_INTEN_PMN3 0x10 /* Enable PMN3 Interrupts */ + +#define XSCALE_EVTSEL_EVT0_MASK 0x000000ff +#define XSCALE_EVTSEL_EVT1_MASK 0x0000ff00 +#define XSCALE_EVTSEL_EVT2_MASK 0x00ff0000 +#define XSCALE_EVTSEL_EVT3_MASK 0xff000000 + +#define XSCALE_FLAG_CCNT_OVERFLOW 0x01 +#define XSCALE_FLAG_PMN0_OVERFLOW 0x02 +#define XSCALE_FLAG_PMN1_OVERFLOW 0x04 +#define XSCALE_FLAG_PMN2_OVERFLOW 0x08 +#define XSCALE_FLAG_PMN3_OVERFLOW 0x10 + +#define XSCALE_RELOAD_COUNT_TO_PERFCTR_VALUE(R) (-(R)) +#define XSCALE_PERFCTR_VALUE_TO_RELOAD_COUNT(P) (-(P)) + +#ifdef _KERNEL +/* MD extension for 'struct pmc' */ +struct pmc_md_xscale_pmc { + uint32_t pm_xscale_evsel; +}; +#endif /* _KERNEL */ +#endif /* _DEV_HWPMC_XSCALE_H_ */ diff --git a/sys/dev/hwpmc/pmc_events.h b/sys/dev/hwpmc/pmc_events.h index 946d4cb5883f..f956b5f7c227 100644 --- a/sys/dev/hwpmc/pmc_events.h +++ b/sys/dev/hwpmc/pmc_events.h @@ -227,6 +227,52 @@ __PMC_EV_ALIAS("unhalted-core-cycles", IAP_ARCH_UNH_COR_CYC) __PMC_EV(UCP, EVENT_0CH_08H_M) \ __PMC_EV(UCP, EVENT_0CH_08H_S) \ +/* + * Intel XScale events from: + * + * Intel XScale Core Developer's Manual + * January, 2004, #27347302 + * + * 3rd Generation Intel XScale Microarchitecture + * Developer's Manual + * May 2007, #31628302 + * + * First 14 events are for 1st and 2nd Generation Intel XScale cores. The + * remaining are available only on 3rd Generation Intel XScale cores. + */ +#define __PMC_EV_XSCALE() \ + __PMC_EV(XSCALE, IC_FETCH) \ + __PMC_EV(XSCALE, IC_MISS) \ + __PMC_EV(XSCALE, DATA_DEPENDENCY_STALLED) \ + __PMC_EV(XSCALE, ITLB_MISS) \ + __PMC_EV(XSCALE, DTLB_MISS) \ + __PMC_EV(XSCALE, BRANCH_RETIRED) \ + __PMC_EV(XSCALE, BRANCH_MISPRED) \ + __PMC_EV(XSCALE, INSTR_RETIRED) \ + __PMC_EV(XSCALE, DC_FULL_CYCLE) \ + __PMC_EV(XSCALE, DC_FULL_CONTIG) \ + __PMC_EV(XSCALE, DC_ACCESS) \ + __PMC_EV(XSCALE, DC_MISS) \ + __PMC_EV(XSCALE, DC_WRITEBACK) \ + __PMC_EV(XSCALE, PC_CHANGE) \ + __PMC_EV(XSCALE, BRANCH_RETIRED_ALL) \ + __PMC_EV(XSCALE, INSTR_CYCLE) \ + __PMC_EV(XSCALE, CP_STALL) \ + __PMC_EV(XSCALE, PC_CHANGE_ALL) \ + __PMC_EV(XSCALE, PIPELINE_FLUSH) \ + __PMC_EV(XSCALE, BACKEND_STALL) \ + __PMC_EV(XSCALE, MULTIPLIER_USE) \ + __PMC_EV(XSCALE, MULTIPLIER_STALLED) \ + __PMC_EV(XSCALE, DATA_CACHE_STALLED) \ + __PMC_EV(XSCALE, L2_CACHE_REQ) \ + __PMC_EV(XSCALE, L2_CACHE_MISS) \ + __PMC_EV(XSCALE, ADDRESS_BUS_TRANS) \ + __PMC_EV(XSCALE, SELF_ADDRESS_BUS_TRANS) \ + __PMC_EV(XSCALE, DATA_BUS_TRANS) + +#define PMC_EV_XSCALE_FIRST PMC_EV_XSCALE_IC_FETCH +#define PMC_EV_XSCALE_LAST PMC_EV_XSCALE_DATA_BUS_TRANS + /* * ARMv7 Events */ @@ -1724,6 +1770,7 @@ __PMC_EV_ALIAS("unhalted-core-cycles", IAP_ARCH_UNH_COR_CYC) * 0x11000 0x0080 INTEL Pentium 4 events * 0x11080 0x0080 INTEL Pentium MMX events * 0x11100 0x0100 INTEL Pentium Pro/P-II/P-III/Pentium-M events + * 0x11200 0x00FF INTEL XScale events * 0x11300 0x00FF MIPS 24K events * 0x11400 0x00FF Octeon events * 0x11500 0x00FF MIPS 74K events @@ -1743,6 +1790,8 @@ __PMC_EV_ALIAS("unhalted-core-cycles", IAP_ARCH_UNH_COR_CYC) __PMC_EV_K7() \ __PMC_EV_BLOCK(K8, 0x2080) \ __PMC_EV_K8() \ + __PMC_EV_BLOCK(XSCALE, 0x11200) \ + __PMC_EV_XSCALE() \ __PMC_EV_BLOCK(MIPS24K, 0x11300) \ __PMC_EV_MIPS24K() \ __PMC_EV_BLOCK(OCTEON, 0x11400) \ diff --git a/sys/sys/pmc.h b/sys/sys/pmc.h index ead5a5694ed3..0c7a3a331abd 100644 --- a/sys/sys/pmc.h +++ b/sys/sys/pmc.h @@ -110,6 +110,7 @@ extern char pmc_cpuid[PMC_CPUID_LEN]; __PMC_CPU(INTEL_BROADWELL_XEON, 0x97, "Intel Broadwell Xeon") \ __PMC_CPU(INTEL_SKYLAKE, 0x98, "Intel Skylake") \ __PMC_CPU(INTEL_SKYLAKE_XEON, 0x99, "Intel Skylake Xeon") \ + __PMC_CPU(INTEL_XSCALE, 0x100, "Intel XScale") \ __PMC_CPU(MIPS_24K, 0x200, "MIPS 24K") \ __PMC_CPU(MIPS_OCTEON, 0x201, "Cavium Octeon") \ __PMC_CPU(MIPS_74K, 0x202, "MIPS 74K") \ @@ -150,6 +151,7 @@ enum pmc_cputype { __PMC_CLASS(IAP, 0x07, "Intel Core...Atom, programmable") \ __PMC_CLASS(UCF, 0x08, "Intel Uncore fixed function") \ __PMC_CLASS(UCP, 0x09, "Intel Uncore programmable") \ + __PMC_CLASS(XSCALE, 0x0A, "Intel XScale counters") \ __PMC_CLASS(MIPS24K, 0x0B, "MIPS 24K") \ __PMC_CLASS(OCTEON, 0x0C, "Cavium Octeon") \ __PMC_CLASS(PPC7450, 0x0D, "Motorola MPC7450 class") \