avionic design with actual uboot and tooling

submodule of avionic design uboot bootloader and with included tools to
get you started , read readme.md and readme-tk1-loader.md
This commit is contained in:
2026-03-03 21:46:32 +02:00
parent fe3ba02c96
commit 68d74d3181
11967 changed files with 2221897 additions and 0 deletions

View File

@@ -0,0 +1,22 @@
menu "MicroBlaze architecture"
depends on MICROBLAZE
config SYS_ARCH
default "microblaze"
choice
prompt "Target select"
optional
config TARGET_MICROBLAZE_GENERIC
bool "Support microblaze-generic"
select SUPPORT_SPL
select OF_CONTROL
select DM
select DM_SERIAL
endchoice
source "board/xilinx/microblaze-generic/Kconfig"
endmenu

View File

@@ -0,0 +1,8 @@
#
# SPDX-License-Identifier: GPL-2.0+
#
head-y := arch/microblaze/cpu/start.o
libs-y += arch/microblaze/cpu/
libs-y += arch/microblaze/lib/

View File

@@ -0,0 +1,21 @@
#
# (C) Copyright 2007-2008 Michal Simek
# Michal SIMEK <monstr@monstr.eu>
#
# (C) Copyright 2004 Atmark Techno, Inc.
# Yasushi SHOJI <yashi@atmark-techno.com>
#
# SPDX-License-Identifier: GPL-2.0+
#
ifeq ($(CROSS_COMPILE),)
CROSS_COMPILE := mb-
endif
CONFIG_STANDALONE_LOAD_ADDR ?= 0x80F00000
PLATFORM_CPPFLAGS += -ffixed-r31 -D__microblaze__
ifeq ($(CONFIG_SPL_BUILD),)
PLATFORM_CPPFLAGS += -fPIC
endif

View File

@@ -0,0 +1,11 @@
#
# (C) Copyright 2000-2006
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
#
# SPDX-License-Identifier: GPL-2.0+
#
extra-y = start.o
obj-y = irq.o
obj-y += interrupts.o cache.o exception.o timer.o
obj-$(CONFIG_SPL_BUILD) += spl.o

View File

@@ -0,0 +1,69 @@
/*
* (C) Copyright 2007 Michal Simek
*
* Michal SIMEK <monstr@monstr.eu>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <asm/asm.h>
int dcache_status (void)
{
int i = 0;
int mask = 0x80;
__asm__ __volatile__ ("mfs %0,rmsr"::"r" (i):"memory");
/* i&=0x80 */
__asm__ __volatile__ ("and %0,%0,%1"::"r" (i), "r" (mask):"memory");
return i;
}
int icache_status (void)
{
int i = 0;
int mask = 0x20;
__asm__ __volatile__ ("mfs %0,rmsr"::"r" (i):"memory");
/* i&=0x20 */
__asm__ __volatile__ ("and %0,%0,%1"::"r" (i), "r" (mask):"memory");
return i;
}
void icache_enable (void) {
MSRSET(0x20);
}
void icache_disable(void) {
/* we are not generate ICACHE size -> flush whole cache */
flush_cache(0, 32768);
MSRCLR(0x20);
}
void dcache_enable (void) {
MSRSET(0x80);
}
void dcache_disable(void) {
#ifdef XILINX_USE_DCACHE
flush_cache(0, XILINX_DCACHE_BYTE_SIZE);
#endif
MSRCLR(0x80);
}
void flush_cache (ulong addr, ulong size)
{
int i;
for (i = 0; i < size; i += 4)
asm volatile (
#ifdef CONFIG_ICACHE
"wic %0, r0;"
#endif
"nop;"
#ifdef CONFIG_DCACHE
"wdc.flush %0, r0;"
#endif
"nop;"
:
: "r" (addr + i)
: "memory");
}

View File

@@ -0,0 +1,64 @@
/*
* (C) Copyright 2007 Michal Simek
*
* Michal SIMEK <monstr@monstr.eu>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <asm/asm.h>
void _hw_exception_handler (void)
{
int address = 0;
int state = 0;
/* loading address of exception EAR */
MFS(address, rear);
/* loading excetpion state register ESR */
MFS(state, resr);
printf("Hardware exception at 0x%x address\n", address);
R17(address);
printf("Return address from exception 0x%x\n", address);
switch (state & 0x1f) { /* mask on exception cause */
case 0x1:
puts("Unaligned data access exception\n");
break;
case 0x2:
puts("Illegal op-code exception\n");
break;
case 0x3:
puts("Instruction bus error exception\n");
break;
case 0x4:
puts("Data bus error exception\n");
break;
case 0x5:
puts("Divide by zero exception\n");
break;
#ifdef MICROBLAZE_V5
case 0x7:
puts("Priviledged or stack protection violation exception\n");
break;
case 0x1000:
puts("Exception in delay slot\n");
break;
#endif
default:
puts("Undefined cause\n");
break;
}
printf("Unaligned %sword access\n", ((state & 0x800) ? "" : "half"));
printf("Unaligned %s access\n", ((state & 0x400) ? "store" : "load"));
printf("Register R%x\n", (state & 0x3E) >> 5);
hang();
}
#ifdef CONFIG_SYS_USR_EXCEP
void _exception_handler (void)
{
puts("User vector_exception\n");
hang();
}
#endif

View File

@@ -0,0 +1,214 @@
/*
* (C) Copyright 2007 Michal Simek
* (C) Copyright 2004 Atmark Techno, Inc.
*
* Michal SIMEK <monstr@monstr.eu>
* Yasushi SHOJI <yashi@atmark-techno.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <command.h>
#include <fdtdec.h>
#include <malloc.h>
#include <asm/microblaze_intc.h>
#include <asm/asm.h>
DECLARE_GLOBAL_DATA_PTR;
void enable_interrupts(void)
{
debug("Enable interrupts for the whole CPU\n");
MSRSET(0x2);
}
int disable_interrupts(void)
{
unsigned int msr;
MFS(msr, rmsr);
MSRCLR(0x2);
return (msr & 0x2) != 0;
}
static struct irq_action *vecs;
static u32 irq_no;
/* mapping structure to interrupt controller */
microblaze_intc_t *intc;
/* default handler */
static void def_hdlr(void)
{
puts("def_hdlr\n");
}
static void enable_one_interrupt(int irq)
{
int mask;
int offset = 1;
offset <<= irq;
mask = intc->ier;
intc->ier = (mask | offset);
debug("Enable one interrupt irq %x - mask %x,ier %x\n", offset, mask,
intc->ier);
debug("INTC isr %x, ier %x, iar %x, mer %x\n", intc->isr, intc->ier,
intc->iar, intc->mer);
}
static void disable_one_interrupt(int irq)
{
int mask;
int offset = 1;
offset <<= irq;
mask = intc->ier;
intc->ier = (mask & ~offset);
debug("Disable one interrupt irq %x - mask %x,ier %x\n", irq, mask,
intc->ier);
debug("INTC isr %x, ier %x, iar %x, mer %x\n", intc->isr, intc->ier,
intc->iar, intc->mer);
}
int install_interrupt_handler(int irq, interrupt_handler_t *hdlr, void *arg)
{
struct irq_action *act;
/* irq out of range */
if ((irq < 0) || (irq > irq_no)) {
puts("IRQ out of range\n");
return -1;
}
act = &vecs[irq];
if (hdlr) { /* enable */
act->handler = hdlr;
act->arg = arg;
act->count = 0;
enable_one_interrupt(irq);
return 0;
}
/* Disable */
act->handler = (interrupt_handler_t *)def_hdlr;
act->arg = (void *)irq;
disable_one_interrupt(irq);
return 1;
}
/* initialization interrupt controller - hardware */
static void intc_init(void)
{
intc->mer = 0;
intc->ier = 0;
intc->iar = 0xFFFFFFFF;
/* XIntc_Start - hw_interrupt enable and all interrupt enable */
intc->mer = 0x3;
debug("INTC isr %x, ier %x, iar %x, mer %x\n", intc->isr, intc->ier,
intc->iar, intc->mer);
}
int interrupt_init(void)
{
int i;
const void *blob = gd->fdt_blob;
int node = 0;
debug("INTC: Initialization\n");
node = fdt_node_offset_by_compatible(blob, node,
"xlnx,xps-intc-1.00.a");
if (node != -1) {
fdt_addr_t base = fdtdec_get_addr(blob, node, "reg");
if (base == FDT_ADDR_T_NONE)
return -1;
debug("INTC: Base addr %lx\n", base);
intc = (microblaze_intc_t *)base;
irq_no = fdtdec_get_int(blob, node, "xlnx,num-intr-inputs", 0);
debug("INTC: IRQ NO %x\n", irq_no);
} else {
return node;
}
if (irq_no) {
vecs = calloc(1, sizeof(struct irq_action) * irq_no);
if (vecs == NULL) {
puts("Interrupt vector allocation failed\n");
return -1;
}
/* initialize irq list */
for (i = 0; i < irq_no; i++) {
vecs[i].handler = (interrupt_handler_t *)def_hdlr;
vecs[i].arg = (void *)i;
vecs[i].count = 0;
}
/* initialize intc controller */
intc_init();
enable_interrupts();
} else {
puts("Undefined interrupt controller\n");
}
return 0;
}
void interrupt_handler(void)
{
int irqs = intc->ivr; /* find active interrupt */
int mask = 1;
int value;
struct irq_action *act = vecs + irqs;
debug("INTC isr %x, ier %x, iar %x, mer %x\n", intc->isr, intc->ier,
intc->iar, intc->mer);
#ifdef DEBUG
R14(value);
#endif
debug("Interrupt handler on %x line, r14 %x\n", irqs, value);
debug("Jumping to interrupt handler rutine addr %x,count %x,arg %x\n",
(u32)act->handler, act->count, (u32)act->arg);
act->handler(act->arg);
act->count++;
intc->iar = mask << irqs;
debug("Dump INTC reg, isr %x, ier %x, iar %x, mer %x\n", intc->isr,
intc->ier, intc->iar, intc->mer);
#ifdef DEBUG
R14(value);
#endif
debug("Interrupt handler on %x line, r14 %x\n", irqs, value);
}
#if defined(CONFIG_CMD_IRQ)
int do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, const char *argv[])
{
int i;
struct irq_action *act = vecs;
if (irq_no) {
puts("\nInterrupt-Information:\n\n"
"Nr Routine Arg Count\n"
"-----------------------------\n");
for (i = 0; i < irq_no; i++) {
if (act->handler != (interrupt_handler_t *)def_hdlr) {
printf("%02d %08x %08x %d\n", i,
(int)act->handler, (int)act->arg,
act->count);
}
act++;
}
puts("\n");
} else {
puts("Undefined interrupt controller\n");
}
return 0;
}
#endif

View File

@@ -0,0 +1,80 @@
/*
* (C) Copyright 2007 Michal Simek
*
* Michal SIMEK <monstr@monstr.eu>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <config.h>
#include <asm/asm.h>
.text
.global _interrupt_handler
_interrupt_handler:
addik r1, r1, -124
swi r2, r1, 4
swi r3, r1, 8
swi r4, r1, 12
swi r5, r1, 16
swi r6, r1, 20
swi r7, r1, 24
swi r8, r1, 28
swi r9, r1, 32
swi r10, r1, 36
swi r11, r1, 40
swi r12, r1, 44
swi r13, r1, 48
swi r14, r1, 52
swi r15, r1, 56
swi r16, r1, 60
swi r17, r1, 64
swi r18, r1, 68
swi r19, r1, 72
swi r20, r1, 76
swi r21, r1, 80
swi r22, r1, 84
swi r23, r1, 88
swi r24, r1, 92
swi r25, r1, 96
swi r26, r1, 100
swi r27, r1, 104
swi r28, r1, 108
swi r29, r1, 112
swi r30, r1, 116
swi r31, r1, 120
brlid r15, interrupt_handler
nop
lwi r31, r1, 120
lwi r30, r1, 116
lwi r29, r1, 112
lwi r28, r1, 108
lwi r27, r1, 104
lwi r26, r1, 100
lwi r25, r1, 96
lwi r24, r1, 92
lwi r23, r1, 88
lwi r22, r1, 84
lwi r21, r1, 80
lwi r20, r1, 76
lwi r19, r1, 72
lwi r18, r1, 68
lwi r17, r1, 64
lwi r16, r1, 60
lwi r15, r1, 56
lwi r14, r1, 52
lwi r13, r1, 48
lwi r12, r1, 44
lwi r11, r1, 40
lwi r10, r1, 36
lwi r9, r1, 32
lwi r8, r1, 28
lwi r7, r1, 24
lwi r6, r1, 20
lwi r5, r1, 16
lwi r4, r1, 12
lwi r3, r1, 8
lwi r2, r1, 4
addik r1, r1, 124
rtid r14, 0
nop
.size _interrupt_handler,.-_interrupt_handler

View File

@@ -0,0 +1,52 @@
/*
* (C) Copyright 2013 - 2014 Xilinx, Inc
*
* Michal Simek <michal.simek@xilinx.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <image.h>
#include <spl.h>
#include <asm/io.h>
#include <asm/u-boot.h>
DECLARE_GLOBAL_DATA_PTR;
bool boot_linux;
u32 spl_boot_device(void)
{
return BOOT_DEVICE_NOR;
}
/* Board initialization after bss clearance */
void spl_board_init(void)
{
/* enable console uart printing */
preloader_console_init();
}
#ifdef CONFIG_SPL_OS_BOOT
void __noreturn jump_to_image_linux(void *arg)
{
debug("Entering kernel arg pointer: 0x%p\n", arg);
typedef void (*image_entry_arg_t)(char *, ulong, ulong)
__attribute__ ((noreturn));
image_entry_arg_t image_entry =
(image_entry_arg_t)spl_image.entry_point;
image_entry(NULL, 0, (ulong)arg);
}
#endif /* CONFIG_SPL_OS_BOOT */
int spl_start_uboot(void)
{
#ifdef CONFIG_SPL_OS_BOOT
if (boot_linux)
return 0;
#endif
return 1;
}

View File

@@ -0,0 +1,322 @@
/*
* (C) Copyright 2007 Michal Simek
* (C) Copyright 2004 Atmark Techno, Inc.
*
* Michal SIMEK <monstr@monstr.eu>
* Yasushi SHOJI <yashi@atmark-techno.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <asm-offsets.h>
#include <config.h>
.text
.global _start
_start:
/*
* reserve registers:
* r10: Stores little/big endian offset for vectors
* r2: Stores imm opcode
* r3: Stores brai opcode
*/
mts rmsr, r0 /* disable cache */
addi r8, r0, __end
mts rslr, r8
/* TODO: Redo this code to call board_init_f_*() */
#if defined(CONFIG_SPL_BUILD)
addi r1, r0, CONFIG_SPL_STACK_ADDR
mts rshr, r1
addi r1, r1, -4 /* Decrement SP to top of memory */
#else
#if defined(CONFIG_SYS_MALLOC_F_LEN)
addi r1, r0, CONFIG_SYS_INIT_SP_OFFSET - CONFIG_SYS_MALLOC_F_LEN
#else
addi r1, r0, CONFIG_SYS_INIT_SP_OFFSET
#endif
mts rshr, r1
addi r1, r1, -4 /* Decrement SP to top of memory */
/* Find-out if u-boot is running on BIG/LITTLE endian platform
* There are some steps which is necessary to keep in mind:
* 1. Setup offset value to r6
* 2. Store word offset value to address 0x0
* 3. Load just byte from address 0x0
* 4a) LITTLE endian - r10 contains 0x2 because it is the smallest
* value that's why is on address 0x0
* 4b) BIG endian - r10 contains 0x0 because 0x2 offset is on addr 0x3
*/
addik r6, r0, 0x2 /* BIG/LITTLE endian offset */
lwi r7, r0, 0x28
swi r6, r0, 0x28 /* used first unused MB vector */
lbui r10, r0, 0x28 /* used first unused MB vector */
swi r7, r0, 0x28
/* add opcode instruction for 32bit jump - 2 instruction imm & brai */
addi r2, r0, 0xb0000000 /* hex b000 opcode imm */
addi r3, r0, 0xb8080000 /* hew b808 opcode brai */
#ifdef CONFIG_SYS_RESET_ADDRESS
/* reset address */
swi r2, r0, 0x0 /* reset address - imm opcode */
swi r3, r0, 0x4 /* reset address - brai opcode */
addik r6, r0, CONFIG_SYS_RESET_ADDRESS
sw r6, r1, r0
lhu r7, r1, r10
rsubi r8, r10, 0x2
sh r7, r0, r8
rsubi r8, r10, 0x6
sh r6, r0, r8
#endif
#ifdef CONFIG_SYS_USR_EXCEP
/* user_vector_exception */
swi r2, r0, 0x8 /* user vector exception - imm opcode */
swi r3, r0, 0xC /* user vector exception - brai opcode */
addik r6, r0, _exception_handler
sw r6, r1, r0
/*
* BIG ENDIAN memory map for user exception
* 0x8: 0xB000XXXX
* 0xC: 0xB808XXXX
*
* then it is necessary to count address for storing the most significant
* 16bits from _exception_handler address and copy it to
* 0xa address. Big endian use offset in r10=0 that's why is it just
* 0xa address. The same is done for the least significant 16 bits
* for 0xe address.
*
* LITTLE ENDIAN memory map for user exception
* 0x8: 0xXXXX00B0
* 0xC: 0xXXXX08B8
*
* Offset is for little endian setup to 0x2. rsubi instruction decrease
* address value to ensure that points to proper place which is
* 0x8 for the most significant 16 bits and
* 0xC for the least significant 16 bits
*/
lhu r7, r1, r10
rsubi r8, r10, 0xa
sh r7, r0, r8
rsubi r8, r10, 0xe
sh r6, r0, r8
#endif
/* interrupt_handler */
swi r2, r0, 0x10 /* interrupt - imm opcode */
swi r3, r0, 0x14 /* interrupt - brai opcode */
addik r6, r0, _interrupt_handler
sw r6, r1, r0
lhu r7, r1, r10
rsubi r8, r10, 0x12
sh r7, r0, r8
rsubi r8, r10, 0x16
sh r6, r0, r8
/* hardware exception */
swi r2, r0, 0x20 /* hardware exception - imm opcode */
swi r3, r0, 0x24 /* hardware exception - brai opcode */
addik r6, r0, _hw_exception_handler
sw r6, r1, r0
lhu r7, r1, r10
rsubi r8, r10, 0x22
sh r7, r0, r8
rsubi r8, r10, 0x26
sh r6, r0, r8
#endif /* BUILD_SPL */
/* Flush cache before enable cache */
addik r5, r0, 0
addik r6, r0, XILINX_DCACHE_BYTE_SIZE
bralid r15, flush_cache
nop
/* enable instruction and data cache */
mfs r12, rmsr
ori r12, r12, 0x1a0
mts rmsr, r12
/* TODO: Redo this code to call board_init_f_*() */
clear_bss:
/* clear BSS segments */
addi r5, r0, __bss_start
addi r4, r0, __bss_end
cmp r6, r5, r4
beqi r6, 3f
2:
swi r0, r5, 0 /* write zero to loc */
addi r5, r5, 4 /* increment to next loc */
cmp r6, r5, r4 /* check if we have reach the end */
bnei r6, 2b
3: /* jumping to board_init */
#ifdef CONFIG_DEBUG_UART
bralid r15, debug_uart_init
nop
#endif
#ifndef CONFIG_SPL_BUILD
or r5, r0, r0 /* flags - empty */
addi r31, r0, _gd
#if defined(CONFIG_SYS_MALLOC_F_LEN)
addi r6, r0, CONFIG_SYS_INIT_SP_OFFSET
swi r6, r31, GD_MALLOC_BASE
#endif
brai board_init_f
#else
addi r31, r0, _gd
#if defined(CONFIG_SYS_MALLOC_F_LEN)
addi r6, r0, CONFIG_SPL_STACK_ADDR
swi r6, r31, GD_MALLOC_BASE
#endif
brai board_init_r
#endif
1: bri 1b
.section .bss
.align 4
_gd:
.space GENERATED_GBL_DATA_SIZE
#ifndef CONFIG_SPL_BUILD
/*
* Read 16bit little endian
*/
.text
.global in16
.ent in16
.align 2
in16: lhu r3, r0, r5
bslli r4, r3, 8
bsrli r3, r3, 8
andi r4, r4, 0xffff
or r3, r3, r4
rtsd r15, 8
sext16 r3, r3
.end in16
/*
* Write 16bit little endian
* first parameter(r5) - address, second(r6) - short value
*/
.text
.global out16
.ent out16
.align 2
out16: bslli r3, r6, 8
bsrli r6, r6, 8
andi r3, r3, 0xffff
or r3, r3, r6
sh r3, r0, r5
rtsd r15, 8
or r0, r0, r0
.end out16
/*
* Relocate u-boot
*/
.text
.global relocate_code
.ent relocate_code
.align 2
relocate_code:
/*
* r5 - start_addr_sp
* r6 - new_gd
* r7 - reloc_addr
*/
addi r1, r5, 0 /* Start to use new SP */
addi r31, r6, 0 /* Start to use new GD */
add r23, r0, r7 /* Move reloc addr to r23 */
/* Relocate text and data - r12 temp value */
addi r21, r0, _start
addi r22, r0, __end - 4 /* Include BSS too */
rsub r6, r21, r22
or r5, r0, r0
1: lw r12, r21, r5 /* Load u-boot data */
sw r12, r23, r5 /* Write zero to loc */
cmp r12, r5, r6 /* Check if we have reach the end */
bneid r12, 1b
addi r5, r5, 4 /* Increment to next loc - relocate code */
/* R23 points to the base address. */
add r23, r0, r7 /* Move reloc addr to r23 */
addi r24, r0, CONFIG_SYS_TEXT_BASE /* Get reloc offset */
rsub r23, r24, r23 /* keep - this is already here gd->reloc_off */
addik r6, r0, 0x2 /* BIG/LITTLE endian offset */
lwi r7, r0, 0x28
swi r6, r0, 0x28 /* used first unused MB vector */
lbui r10, r0, 0x28 /* used first unused MB vector */
swi r7, r0, 0x28
#ifdef CONFIG_SYS_USR_EXCEP
addik r6, r0, _exception_handler
addk r6, r6, r23 /* add offset */
sw r6, r1, r0
lhu r7, r1, r10
rsubi r8, r10, 0xa
sh r7, r0, r8
rsubi r8, r10, 0xe
sh r6, r0, r8
#endif
addik r6, r0, _hw_exception_handler
addk r6, r6, r23 /* add offset */
sw r6, r1, r0
lhu r7, r1, r10
rsubi r8, r10, 0x22
sh r7, r0, r8
rsubi r8, r10, 0x26
sh r6, r0, r8
addik r6, r0, _interrupt_handler
addk r6, r6, r23 /* add offset */
sw r6, r1, r0
lhu r7, r1, r10
rsubi r8, r10, 0x12
sh r7, r0, r8
rsubi r8, r10, 0x16
sh r6, r0, r8
/* Check if GOT exist */
addik r21, r23, _got_start
addik r22, r23, _got_end
cmpu r12, r21, r22
beqi r12, 2f /* No GOT table - jump over */
/* Skip last 3 entries plus 1 because of loop boundary below */
addik r22, r22, -0x10
/* Relocate the GOT. */
3: lw r12, r21, r0 /* Load entry */
addk r12, r12, r23 /* Add reloc offset */
sw r12, r21, r0 /* Save entry back */
cmpu r12, r21, r22 /* Check if this cross boundary */
bneid r12, 3b
addik r21. r21, 4
/* Update pointer to GOT */
mfs r20, rpc
addik r20, r20, _GLOBAL_OFFSET_TABLE_ + 8
addk r20, r20, r23
/* Flush caches to ensure consistency */
addik r5, r0, 0
addik r6, r0, XILINX_DCACHE_BYTE_SIZE
bralid r15, flush_cache
nop
2: addi r5, r31, 0 /* gd is initialized in board_r.c */
addi r6, r0, CONFIG_SYS_TEXT_BASE
addi r12, r23, board_init_r
bra r12 /* Jump to relocated code */
.end relocate_code
#endif

View File

@@ -0,0 +1,115 @@
/*
* (C) Copyright 2007 Michal Simek
*
* Michal SIMEK <monstr@monstr.eu>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <fdtdec.h>
#include <asm/microblaze_timer.h>
#include <asm/microblaze_intc.h>
DECLARE_GLOBAL_DATA_PTR;
volatile int timestamp = 0;
microblaze_timer_t *tmr;
ulong get_timer (ulong base)
{
if (tmr)
return timestamp - base;
return timestamp++ - base;
}
void __udelay(unsigned long usec)
{
u32 i;
if (tmr) {
i = get_timer(0);
while ((get_timer(0) - i) < (usec / 1000))
;
}
}
#ifndef CONFIG_SPL_BUILD
static void timer_isr(void *arg)
{
timestamp++;
tmr->control = tmr->control | TIMER_INTERRUPT;
}
int timer_init (void)
{
int irq = -1;
u32 preload = 0;
u32 ret = 0;
const void *blob = gd->fdt_blob;
int node = 0;
u32 cell[2];
debug("TIMER: Initialization\n");
node = fdt_node_offset_by_compatible(blob, node,
"xlnx,xps-timer-1.00.a");
if (node != -1) {
fdt_addr_t base = fdtdec_get_addr(blob, node, "reg");
if (base == FDT_ADDR_T_NONE)
return -1;
debug("TIMER: Base addr %lx\n", base);
tmr = (microblaze_timer_t *)base;
ret = fdtdec_get_int_array(blob, node, "interrupts",
cell, ARRAY_SIZE(cell));
if (ret)
return ret;
irq = cell[0];
debug("TIMER: IRQ %x\n", irq);
preload = fdtdec_get_int(blob, node, "clock-frequency", 0);
preload /= CONFIG_SYS_HZ;
} else {
return node;
}
if (tmr && preload && irq >= 0) {
tmr->loadreg = preload;
tmr->control = TIMER_INTERRUPT | TIMER_RESET;
tmr->control = TIMER_ENABLE | TIMER_ENABLE_INTR |\
TIMER_RELOAD | TIMER_DOWN_COUNT;
timestamp = 0;
ret = install_interrupt_handler (irq, timer_isr, (void *)tmr);
if (ret)
tmr = NULL;
}
/* No problem if timer is not found/initialized */
return 0;
}
#else
int timer_init(void)
{
return 0;
}
#endif
/*
* This function is derived from PowerPC code (read timebase as long long).
* On Microblaze it just returns the timer value.
*/
unsigned long long get_ticks(void)
{
return get_timer(0);
}
/*
* This function is derived from PowerPC code (timebase clock frequency).
* On Microblaze it returns the number of timer ticks per second.
*/
ulong get_tbclk(void)
{
return CONFIG_SYS_HZ;
}

View File

@@ -0,0 +1,63 @@
/*
* (C) Copyright 2013 - 2014 Xilinx, Inc
*
* Michal Simek <michal.simek@xilinx.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <asm-offsets.h>
OUTPUT_ARCH(microblaze)
ENTRY(_start)
SECTIONS
{
.text ALIGN(0x4):
{
__text_start = .;
arch/microblaze/cpu/start.o (.text)
*(.text)
*(.text.*)
__text_end = .;
}
.rodata ALIGN(0x4):
{
__rodata_start = .;
*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
__rodata_end = .;
}
.data ALIGN(0x4):
{
__data_start = .;
*(.data)
*(.data.*)
__data_end = .;
}
. = ALIGN(4);
.u_boot_list : {
KEEP(*(SORT(.u_boot_list*)));
}
__init_end = . ;
.bss ALIGN(0x4):
{
__bss_start = .;
*(.sbss)
*(.scommon)
*(.bss)
*(.bss.*)
*(COMMON)
. = ALIGN(4);
__bss_end = .;
}
__end = . ;
}
#if defined(CONFIG_SPL_MAX_FOOTPRINT)
ASSERT(__end - _start < (CONFIG_SPL_MAX_FOOTPRINT), \
"SPL image plus BSS too big");
#endif

View File

@@ -0,0 +1,61 @@
/*
* (C) Copyright 2004 Atmark Techno, Inc.
*
* Yasushi SHOJI <yashi@atmark-techno.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
OUTPUT_ARCH(microblaze)
ENTRY(_start)
SECTIONS
{
.text ALIGN(0x4):
{
__text_start = .;
arch/microblaze/cpu/start.o (.text)
*(.text)
__text_end = .;
}
.rodata ALIGN(0x4):
{
__rodata_start = .;
*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
__rodata_end = .;
}
.data ALIGN(0x4):
{
__data_start = .;
*(.data)
__data_end = .;
}
.got ALIGN(4):
{
_got_start = .;
*(.got*)
. = ALIGN(4);
_got_end = .;
}
. = ALIGN(4);
.u_boot_list : {
KEEP(*(SORT(.u_boot_list*)));
}
__init_end = . ;
.bss ALIGN(0x4):
{
__bss_start = .;
*(.sbss)
*(.scommon)
*(.bss)
*(COMMON)
. = ALIGN(4);
__bss_end = .;
}
__end = . ;
}

1
u-boot/arch/microblaze/dts/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
*.dtb

View File

@@ -0,0 +1,15 @@
#
# SPDX-License-Identifier: GPL-2.0+
#
dtb-y += microblaze-generic.dtb
targets += $(dtb-y)
DTC_FLAGS += -R 4 -p 0x1000
PHONY += dtbs
dtbs: $(addprefix $(obj)/, $(dtb-y))
@:
clean-files := *.dtb

View File

@@ -0,0 +1 @@
../../../../include/dt-bindings

View File

@@ -0,0 +1,9 @@
/dts-v1/;
/ {
#address-cells = <1>;
#size-cells = <1>;
aliases {
} ;
chosen {
} ;
} ;

View File

@@ -0,0 +1,86 @@
/*
* (C) Copyright 2007 Michal Simek
*
* Michal SIMEK <monstr@monstr.eu>
*
* SPDX-License-Identifier: GPL-2.0+
*/
/* FSL macros */
#define NGET(val, fslnum) \
__asm__ __volatile__ ("nget %0, rfsl" #fslnum :"=r" (val));
#define GET(val, fslnum) \
__asm__ __volatile__ ("get %0, rfsl" #fslnum :"=r" (val));
#define NCGET(val, fslnum) \
__asm__ __volatile__ ("ncget %0, rfsl" #fslnum :"=r" (val));
#define CGET(val, fslnum) \
__asm__ __volatile__ ("cget %0, rfsl" #fslnum :"=r" (val));
#define NPUT(val, fslnum) \
__asm__ __volatile__ ("nput %0, rfsl" #fslnum ::"r" (val));
#define PUT(val, fslnum) \
__asm__ __volatile__ ("put %0, rfsl" #fslnum ::"r" (val));
#define NCPUT(val, fslnum) \
__asm__ __volatile__ ("ncput %0, rfsl" #fslnum ::"r" (val));
#define CPUT(val, fslnum) \
__asm__ __volatile__ ("cput %0, rfsl" #fslnum ::"r" (val));
/* CPU dependent */
/* machine status register */
#define MFS(val, reg) \
__asm__ __volatile__ ("mfs %0," #reg :"=r" (val));
#define MTS(val, reg) \
__asm__ __volatile__ ("mts " #reg ", %0"::"r" (val));
/* get return address from interrupt */
#define R14(val) \
__asm__ __volatile__ ("addi %0, r14, 0":"=r" (val));
/* get return address from interrupt */
#define R17(val) \
__asm__ __volatile__ ("addi %0, r17, 0" : "=r" (val));
#define NOP __asm__ __volatile__ ("nop");
/* use machine status registe USE_MSR_REG */
#if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR == 1
#define MSRSET(val) \
__asm__ __volatile__ ("msrset r0," #val );
#define MSRCLR(val) \
__asm__ __volatile__ ("msrclr r0," #val );
#else
#define MSRSET(val) \
{ \
register unsigned tmp; \
__asm__ __volatile__ (" \
mfs %0, rmsr; \
ori %0, %0, "#val"; \
mts rmsr, %0; \
nop;" \
: "=r" (tmp) \
: "d" (val) \
: "memory"); \
}
#define MSRCLR(val) \
{ \
register unsigned tmp; \
__asm__ __volatile__ (" \
mfs %0, rmsr; \
andi %0, %0, ~"#val"; \
mts rmsr, %0; \
nop;" \
: "=r" (tmp) \
: "d" (val) \
: "memory"); \
}
#endif

View File

@@ -0,0 +1,375 @@
#ifndef _MICROBLAZE_BITOPS_H
#define _MICROBLAZE_BITOPS_H
/*
* Copyright 1992, Linus Torvalds.
*/
#include <asm/byteorder.h> /* swab32 */
#include <asm/system.h> /* save_flags */
#include <asm-generic/bitops/fls.h>
#include <asm-generic/bitops/__fls.h>
#include <asm-generic/bitops/fls64.h>
#include <asm-generic/bitops/__ffs.h>
#ifdef __KERNEL__
/*
* The __ functions are not atomic
*/
/*
* ffz = Find First Zero in word. Undefined if no zero exists,
* so code should check against ~0UL first..
*/
static inline unsigned long ffz(unsigned long word)
{
unsigned long result = 0;
while(word & 1) {
result++;
word >>= 1;
}
return result;
}
static inline void set_bit(int nr, volatile void *addr)
{
int * a = (int *) addr;
int mask;
unsigned long flags;
a += nr >> 5;
mask = 1 << (nr & 0x1f);
save_flags_cli(flags);
*a |= mask;
restore_flags(flags);
}
static inline void __set_bit(int nr, volatile void *addr)
{
int * a = (int *) addr;
int mask;
a += nr >> 5;
mask = 1 << (nr & 0x1f);
*a |= mask;
}
#define PLATFORM__SET_BIT
/*
* clear_bit() doesn't provide any barrier for the compiler.
*/
#define smp_mb__before_clear_bit() barrier()
#define smp_mb__after_clear_bit() barrier()
static inline void clear_bit(int nr, volatile void *addr)
{
int * a = (int *) addr;
int mask;
unsigned long flags;
a += nr >> 5;
mask = 1 << (nr & 0x1f);
save_flags_cli(flags);
*a &= ~mask;
restore_flags(flags);
}
#define __clear_bit(nr, addr) clear_bit(nr, addr)
#define PLATFORM__CLEAR_BIT
static inline void change_bit(int nr, volatile void *addr)
{
int mask;
unsigned long flags;
unsigned long *ADDR = (unsigned long *) addr;
ADDR += nr >> 5;
mask = 1 << (nr & 31);
save_flags_cli(flags);
*ADDR ^= mask;
restore_flags(flags);
}
static inline void __change_bit(int nr, volatile void *addr)
{
int mask;
unsigned long *ADDR = (unsigned long *) addr;
ADDR += nr >> 5;
mask = 1 << (nr & 31);
*ADDR ^= mask;
}
static inline int test_and_set_bit(int nr, volatile void *addr)
{
int mask, retval;
volatile unsigned int *a = (volatile unsigned int *) addr;
unsigned long flags;
a += nr >> 5;
mask = 1 << (nr & 0x1f);
save_flags_cli(flags);
retval = (mask & *a) != 0;
*a |= mask;
restore_flags(flags);
return retval;
}
static inline int __test_and_set_bit(int nr, volatile void *addr)
{
int mask, retval;
volatile unsigned int *a = (volatile unsigned int *) addr;
a += nr >> 5;
mask = 1 << (nr & 0x1f);
retval = (mask & *a) != 0;
*a |= mask;
return retval;
}
static inline int test_and_clear_bit(int nr, volatile void *addr)
{
int mask, retval;
volatile unsigned int *a = (volatile unsigned int *) addr;
unsigned long flags;
a += nr >> 5;
mask = 1 << (nr & 0x1f);
save_flags_cli(flags);
retval = (mask & *a) != 0;
*a &= ~mask;
restore_flags(flags);
return retval;
}
static inline int __test_and_clear_bit(int nr, volatile void *addr)
{
int mask, retval;
volatile unsigned int *a = (volatile unsigned int *) addr;
a += nr >> 5;
mask = 1 << (nr & 0x1f);
retval = (mask & *a) != 0;
*a &= ~mask;
return retval;
}
static inline int test_and_change_bit(int nr, volatile void *addr)
{
int mask, retval;
volatile unsigned int *a = (volatile unsigned int *) addr;
unsigned long flags;
a += nr >> 5;
mask = 1 << (nr & 0x1f);
save_flags_cli(flags);
retval = (mask & *a) != 0;
*a ^= mask;
restore_flags(flags);
return retval;
}
static inline int __test_and_change_bit(int nr, volatile void *addr)
{
int mask, retval;
volatile unsigned int *a = (volatile unsigned int *) addr;
a += nr >> 5;
mask = 1 << (nr & 0x1f);
retval = (mask & *a) != 0;
*a ^= mask;
return retval;
}
/*
* This routine doesn't need to be atomic.
*/
static inline int __constant_test_bit(int nr, const volatile void *addr)
{
return ((1UL << (nr & 31)) & (((const volatile unsigned int *) addr)[nr >> 5])) != 0;
}
static inline int __test_bit(int nr, volatile void *addr)
{
int * a = (int *) addr;
int mask;
a += nr >> 5;
mask = 1 << (nr & 0x1f);
return ((mask & *a) != 0);
}
#define test_bit(nr,addr) \
(__builtin_constant_p(nr) ? \
__constant_test_bit((nr),(addr)) : \
__test_bit((nr),(addr)))
#define find_first_zero_bit(addr, size) \
find_next_zero_bit((addr), (size), 0)
static inline int find_next_zero_bit(void *addr, int size, int offset)
{
unsigned long *p = ((unsigned long *) addr) + (offset >> 5);
unsigned long result = offset & ~31UL;
unsigned long tmp;
if (offset >= size)
return size;
size -= result;
offset &= 31UL;
if (offset) {
tmp = *(p++);
tmp |= ~0UL >> (32-offset);
if (size < 32)
goto found_first;
if (~tmp)
goto found_middle;
size -= 32;
result += 32;
}
while (size & ~31UL) {
if (~(tmp = *(p++)))
goto found_middle;
result += 32;
size -= 32;
}
if (!size)
return result;
tmp = *p;
found_first:
tmp |= ~0UL >> size;
found_middle:
return result + ffz(tmp);
}
/*
* hweightN: returns the hamming weight (i.e. the number
* of bits set) of a N-bit word
*/
#define hweight32(x) generic_hweight32(x)
#define hweight16(x) generic_hweight16(x)
#define hweight8(x) generic_hweight8(x)
static inline int ext2_set_bit(int nr, volatile void *addr)
{
int mask, retval;
unsigned long flags;
volatile unsigned char *ADDR = (unsigned char *) addr;
ADDR += nr >> 3;
mask = 1 << (nr & 0x07);
save_flags_cli(flags);
retval = (mask & *ADDR) != 0;
*ADDR |= mask;
restore_flags(flags);
return retval;
}
static inline int ext2_clear_bit(int nr, volatile void *addr)
{
int mask, retval;
unsigned long flags;
volatile unsigned char *ADDR = (unsigned char *) addr;
ADDR += nr >> 3;
mask = 1 << (nr & 0x07);
save_flags_cli(flags);
retval = (mask & *ADDR) != 0;
*ADDR &= ~mask;
restore_flags(flags);
return retval;
}
static inline int ext2_test_bit(int nr, const volatile void *addr)
{
int mask;
const volatile unsigned char *ADDR = (const unsigned char *) addr;
ADDR += nr >> 3;
mask = 1 << (nr & 0x07);
return ((mask & *ADDR) != 0);
}
#define ext2_find_first_zero_bit(addr, size) \
ext2_find_next_zero_bit((addr), (size), 0)
static inline unsigned long ext2_find_next_zero_bit(void *addr,
unsigned long size, unsigned long offset)
{
unsigned long *p = ((unsigned long *) addr) + (offset >> 5);
unsigned long result = offset & ~31UL;
unsigned long tmp;
if (offset >= size)
return size;
size -= result;
offset &= 31UL;
if(offset) {
/* We hold the little endian value in tmp, but then the
* shift is illegal. So we could keep a big endian value
* in tmp, like this:
*
* tmp = __swab32(*(p++));
* tmp |= ~0UL >> (32-offset);
*
* but this would decrease preformance, so we change the
* shift:
*/
tmp = *(p++);
tmp |= __swab32(~0UL >> (32-offset));
if(size < 32)
goto found_first;
if(~tmp)
goto found_middle;
size -= 32;
result += 32;
}
while(size & ~31UL) {
if(~(tmp = *(p++)))
goto found_middle;
result += 32;
size -= 32;
}
if(!size)
return result;
tmp = *p;
found_first:
/* tmp is little endian, so we would have to swab the shift,
* see above. But then we have to swab tmp below for ffz, so
* we might as well do this here.
*/
return result + ffz(__swab32(tmp) | (~0UL << size));
found_middle:
return result + ffz(__swab32(tmp));
}
/* Bitmap functions for the minix filesystem. */
#define minix_test_and_set_bit(nr,addr) test_and_set_bit(nr,addr)
#define minix_set_bit(nr,addr) set_bit(nr,addr)
#define minix_test_and_clear_bit(nr,addr) test_and_clear_bit(nr,addr)
#define minix_test_bit(nr,addr) test_bit(nr,addr)
#define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size)
/**
* hweightN - returns the hamming weight of a N-bit word
* @x: the word to weigh
*
* The Hamming Weight of a number is the total number of bits set in it.
*/
#define hweight32(x) generic_hweight32(x)
#define hweight16(x) generic_hweight16(x)
#define hweight8(x) generic_hweight8(x)
#endif /* __KERNEL__ */
#endif /* _MICROBLAZE_BITOPS_H */

View File

@@ -0,0 +1,36 @@
/*
* include/asm-microblaze/byteorder.h -- Endian id and conversion ops
*
* Copyright (C) 2003 John Williams <jwilliams@itee.uq.edu.au>
* Copyright (C) 2001 NEC Corporation
* Copyright (C) 2001 Miles Bader <miles@gnu.org>
*
* This file is subject to the terms and conditions of the GNU General
* Public License. See the file COPYING in the main directory of this
* archive for more details.
*
* Written by Miles Bader <miles@gnu.org>
* Microblaze port by John Williams
*/
#ifndef __MICROBLAZE_BYTEORDER_H__
#define __MICROBLAZE_BYTEORDER_H__
#include <asm/types.h>
#ifdef __GNUC__
#if !defined(__STRICT_ANSI__) || defined(__KERNEL__)
# define __BYTEORDER_HAS_U64__
# define __SWAB_64_THRU_32__
#endif
#endif /* __GNUC__ */
#ifdef __MICROBLAZEEL__
#include <linux/byteorder/little_endian.h>
#else
#include <linux/byteorder/big_endian.h>
#endif
#endif /* __MICROBLAZE_BYTEORDER_H__ */

View File

@@ -0,0 +1,22 @@
/*
* Copyright (c) 2011 The Chromium OS Authors.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#ifndef __MICROBLAZE_CACHE_H__
#define __MICROBLAZE_CACHE_H__
/*
* The microblaze can have either a 4 or 16 byte cacheline depending on whether
* you are using OPB(4) or CacheLink(16). If the board config has not specified
* a cacheline size we assume the larger value of 16 bytes for DMA buffer
* alignment.
*/
#ifdef CONFIG_SYS_CACHELINE_SIZE
#define ARCH_DMA_MINALIGN CONFIG_SYS_CACHELINE_SIZE
#else
#define ARCH_DMA_MINALIGN 16
#endif
#endif /* __MICROBLAZE_CACHE_H__ */

View File

@@ -0,0 +1,16 @@
/*
* Copyright 2009 Freescale Semiconductor, Inc.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#ifndef _ASM_CONFIG_H_
#define _ASM_CONFIG_H_
#ifndef CONFIG_SPL_BUILD
#define CONFIG_NEEDS_MANUAL_RELOC
#endif
#define CONFIG_NR_DRAM_BANKS 1
#endif

View File

@@ -0,0 +1 @@
#include <asm-generic/errno.h>

View File

@@ -0,0 +1,20 @@
/*
* (C) Copyright 2004 Atmark Techno, Inc.
*
* Yasushi SHOJI <yashi@atmark-techno.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#ifndef __ASM_GBL_DATA_H
#define __ASM_GBL_DATA_H
/* Architecture-specific global data */
struct arch_global_data {
};
#include <asm-generic/global_data.h>
#define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("r31")
#endif /* __ASM_GBL_DATA_H */

View File

@@ -0,0 +1,14 @@
#ifndef _ASM_MICROBLAZE_GPIO_H_
#define _ASM_MICROBLAZE_GPIO_H_
#include <asm-generic/gpio.h>
/* Allocation functions */
extern int gpio_alloc_dual(u32 baseaddr, const char *name, u32 gpio_no0,
u32 gpio_no1);
extern int gpio_alloc(u32 baseaddr, const char *name, u32 gpio_no);
#define gpio_status() gpio_info()
extern void gpio_info(void);
#endif

View File

@@ -0,0 +1,163 @@
/*
* include/asm-microblaze/io.h -- Misc I/O operations
*
* Copyright (C) 2003 John Williams <jwilliams@itee.uq.edu.au>
* Copyright (C) 2001,02 NEC Corporation
* Copyright (C) 2001,02 Miles Bader <miles@gnu.org>
*
* This file is subject to the terms and conditions of the GNU General
* Public License. See the file COPYING in the main directory of this
* archive for more details.
*
* Written by Miles Bader <miles@gnu.org>
* Microblaze port by John Williams
*/
#ifndef __MICROBLAZE_IO_H__
#define __MICROBLAZE_IO_H__
#include <asm/types.h>
#define IO_SPACE_LIMIT 0xFFFFFFFF
#define readb(addr) \
({ unsigned char __v = (*(volatile unsigned char *) (addr)); __v; })
#define readw(addr) \
({ unsigned short __v = (*(volatile unsigned short *) (addr)); __v; })
#define readl(addr) \
({ unsigned int __v = (*(volatile unsigned int *) (addr)); __v; })
#define writeb(b, addr) \
(void)((*(volatile unsigned char *) (addr)) = (b))
#define writew(b, addr) \
(void)((*(volatile unsigned short *) (addr)) = (b))
#define writel(b, addr) \
(void)((*(volatile unsigned int *) (addr)) = (b))
#define memset_io(a,b,c) memset((void *)(a),(b),(c))
#define memcpy_fromio(a,b,c) memcpy((a),(void *)(b),(c))
#define memcpy_toio(a,b,c) memcpy((void *)(a),(b),(c))
#define inb(addr) readb (addr)
#define inw(addr) readw (addr)
#define inl(addr) readl (addr)
#define outb(x, addr) ((void) writeb (x, addr))
#define outw(x, addr) ((void) writew (x, addr))
#define outl(x, addr) ((void) writel (x, addr))
/* Some #definitions to keep strange Xilinx code happy */
#define in_8(addr) readb (addr)
#define in_be16(addr) readw (addr)
#define in_be32(addr) readl (addr)
#define out_8(addr,x ) outb (x,addr)
#define out_be16(addr,x ) outw (x,addr)
#define out_be32(addr,x ) outl (x,addr)
#define inb_p(port) inb((port))
#define outb_p(val, port) outb((val), (port))
#define inw_p(port) inw((port))
#define outw_p(val, port) outw((val), (port))
#define inl_p(port) inl((port))
#define outl_p(val, port) outl((val), (port))
/* Some defines to keep the MTD flash drivers happy */
#define __raw_readb readb
#define __raw_readw readw
#define __raw_readl readl
#define __raw_writeb writeb
#define __raw_writew writew
#define __raw_writel writel
static inline void io_insb (unsigned long port, void *dst, unsigned long count)
{
unsigned char *p = dst;
while (count--)
*p++ = inb (port);
}
static inline void io_insw (unsigned long port, void *dst, unsigned long count)
{
unsigned short *p = dst;
while (count--)
*p++ = inw (port);
}
static inline void io_insl (unsigned long port, void *dst, unsigned long count)
{
unsigned long *p = dst;
while (count--)
*p++ = inl (port);
}
static inline void
io_outsb (unsigned long port, const void *src, unsigned long count)
{
const unsigned char *p = src;
while (count--)
outb (*p++, port);
}
static inline void
io_outsw (unsigned long port, const void *src, unsigned long count)
{
const unsigned short *p = src;
while (count--)
outw (*p++, port);
}
static inline void
io_outsl (unsigned long port, const void *src, unsigned long count)
{
const unsigned long *p = src;
while (count--)
outl (*p++, port);
}
#define outsb(a,b,l) io_outsb(a,b,l)
#define outsw(a,b,l) io_outsw(a,b,l)
#define outsl(a,b,l) io_outsl(a,b,l)
#define insb(a,b,l) io_insb(a,b,l)
#define insw(a,b,l) io_insw(a,b,l)
#define insl(a,b,l) io_insl(a,b,l)
#define iounmap(addr) ((void)0)
#define ioremap(physaddr, size) (physaddr)
#define ioremap_nocache(physaddr, size) (physaddr)
#define ioremap_writethrough(physaddr, size) (physaddr)
#define ioremap_fullcache(physaddr, size) (physaddr)
static inline void sync(void)
{
}
/*
* Given a physical address and a length, return a virtual address
* that can be used to access the memory range with the caching
* properties specified by "flags".
*/
#define MAP_NOCACHE (0)
#define MAP_WRCOMBINE (0)
#define MAP_WRBACK (0)
#define MAP_WRTHROUGH (0)
static inline void *
map_physmem(phys_addr_t paddr, unsigned long len, unsigned long flags)
{
return (void *)paddr;
}
/*
* Take down a mapping set up by map_physmem().
*/
static inline void unmap_physmem(void *vaddr, unsigned long flags)
{
}
static inline phys_addr_t virt_to_phys(void * vaddr)
{
return (phys_addr_t)(vaddr);
}
#endif /* __MICROBLAZE_IO_H__ */

View File

@@ -0,0 +1,36 @@
/*
* (C) Copyright 2007 Michal Simek
*
* Michal SIMEK <monstr@monstr.cz>
*
* SPDX-License-Identifier: GPL-2.0+
*/
typedef volatile struct microblaze_intc_t {
int isr; /* interrupt status register */
int ipr; /* interrupt pending register */
int ier; /* interrupt enable register */
int iar; /* interrupt acknowledge register */
int sie; /* set interrupt enable bits */
int cie; /* clear interrupt enable bits */
int ivr; /* interrupt vector register */
int mer; /* master enable register */
} microblaze_intc_t;
struct irq_action {
interrupt_handler_t *handler; /* pointer to interrupt rutine */
void *arg;
int count; /* number of interrupt */
};
/**
* Register and unregister interrupt handler rutines
*
* @param irq IRQ number
* @param hdlr Interrupt handler rutine
* @param arg Pointer to argument which is passed to int. handler rutine
* @return 0 if registration pass, 1 if unregistration pass,
* or an error code < 0 otherwise
*/
int install_interrupt_handler(int irq, interrupt_handler_t *hdlr,
void *arg);

View File

@@ -0,0 +1,27 @@
/*
* (C) Copyright 2007 Michal Simek
*
* Michal SIMEK <monstr@monstr.cz>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#define TIMER_ENABLE_ALL 0x400 /* ENALL */
#define TIMER_PWM 0x200 /* PWMA0 */
#define TIMER_INTERRUPT 0x100 /* T0INT */
#define TIMER_ENABLE 0x080 /* ENT0 */
#define TIMER_ENABLE_INTR 0x040 /* ENIT0 */
#define TIMER_RESET 0x020 /* LOAD0 */
#define TIMER_RELOAD 0x010 /* ARHT0 */
#define TIMER_EXT_CAPTURE 0x008 /* CAPT0 */
#define TIMER_EXT_COMPARE 0x004 /* GENT0 */
#define TIMER_DOWN_COUNT 0x002 /* UDT0 */
#define TIMER_CAPTURE_MODE 0x001 /* MDT0 */
typedef volatile struct microblaze_timer_t {
int control; /* control/statuc register TCSR */
int loadreg; /* load register TLR */
int counter; /* timer/counter register */
} microblaze_timer_t;
int timer_init(void);

View File

@@ -0,0 +1,77 @@
/*
* include/asm-microblaze/posix_types.h -- Kernel versions of standard types
*
* Copyright (C) 2003 John Williams <jwilliams@itee.uq.edu.au>
* Copyright (C) 2001,2002 NEC Corporation
* Copyright (C) 2001,2002 Miles Bader <miles@gnu.org>
*
* This file is subject to the terms and conditions of the GNU General
* Public License. See the file COPYING in the main directory of this
* archive for more details.
*
* Written by Miles Bader <miles@gnu.org>
* Microblaze port by John Williams
*/
#ifndef __MICROBLAZE_POSIX_TYPES_H__
#define __MICROBLAZE_POSIX_TYPES_H__
typedef unsigned int __kernel_dev_t;
typedef unsigned long __kernel_ino_t;
typedef unsigned long long __kernel_ino64_t;
typedef unsigned int __kernel_mode_t;
typedef unsigned int __kernel_nlink_t;
typedef long __kernel_off_t;
typedef long long __kernel_loff_t;
typedef int __kernel_pid_t;
typedef unsigned short __kernel_ipc_pid_t;
typedef unsigned int __kernel_uid_t;
typedef unsigned int __kernel_gid_t;
#ifdef __GNUC__
typedef __SIZE_TYPE__ __kernel_size_t;
#else
typedef unsigned int __kernel_size_t;
#endif
typedef int __kernel_ssize_t;
typedef int __kernel_ptrdiff_t;
typedef long __kernel_time_t;
typedef long __kernel_suseconds_t;
typedef long __kernel_clock_t;
typedef int __kernel_daddr_t;
typedef char * __kernel_caddr_t;
typedef unsigned short __kernel_uid16_t;
typedef unsigned short __kernel_gid16_t;
typedef unsigned int __kernel_uid32_t;
typedef unsigned int __kernel_gid32_t;
typedef unsigned short __kernel_old_uid_t;
typedef unsigned short __kernel_old_gid_t;
typedef struct {
#if defined(__KERNEL__) || defined(__USE_ALL)
int val[2];
#else /* !defined(__KERNEL__) && !defined(__USE_ALL) */
int __val[2];
#endif /* !defined(__KERNEL__) && !defined(__USE_ALL) */
} __kernel_fsid_t;
#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)
#undef __FD_SET
#define __FD_SET(fd, fd_set) \
__set_bit (fd, (void *)&((__kernel_fd_set *)fd_set)->fds_bits)
#undef __FD_CLR
#define __FD_CLR(fd, fd_set) \
__clear_bit (fd, (void *)&((__kernel_fd_set *)fd_set)->fds_bits)
#undef __FD_ISSET
#define __FD_ISSET(fd, fd_set) \
__test_bit (fd, (void *)&((__kernel_fd_set *)fd_set)->fds_bits)
#undef __FD_ZERO
#define __FD_ZERO(fd_set) \
memset (fd_set, 0, sizeof (*(fd_set *)fd_set))
#endif /* defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) */
#endif /* __MICROBLAZE_POSIX_TYPES_H__ */

View File

@@ -0,0 +1,21 @@
/*
* Copyright (C) 2011 Michal Simek <monstr@monstr.eu>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#ifndef __ASM_MICROBLAZE_PROCESSOR_H
#define __ASM_MICROBLAZE_PROCESSOR_H
/* References to section boundaries */
extern char __end[];
extern char __text_start[];
/* Microblaze board initialization function */
void board_init(void);
/* Watchdog functions */
extern void hw_watchdog_disable(void);
#endif /* __ASM_MICROBLAZE_PROCESSOR_H */

View File

@@ -0,0 +1,116 @@
/*
* include/asm-microblaze/ptrace.h -- Access to CPU registers
*
* Copyright (C) 2003 John Williams <jwilliams@itee.uq.edu.au>
* Copyright (C) 2001,2002 NEC Corporation
* Copyright (C) 2001,2002 Miles Bader <miles@gnu.org>
*
* This file is subject to the terms and conditions of the GNU General
* Public License. See the file COPYING in the main directory of this
* archive for more details.
*
* Written by Miles Bader <miles@gnu.org>
* Microblaze port by John Williams
*/
#ifndef __MICROBLAZE_PTRACE_H__
#define __MICROBLAZE_PTRACE_H__
/* Microblaze general purpose registers with special meanings. */
#define GPR_ZERO 0 /* constant zero */
#define GPR_ASM 18 /* reserved for assembler */
#define GPR_SP 1 /* stack pointer */
#define GPR_GP 2 /* global data pointer */
#define GPR_EP 30 /* `element pointer' */
#define GPR_LP 15 /* link pointer (current return address) */
/* These aren't official names, but they make some code more descriptive. */
#define GPR_ARG0 5
#define GPR_ARG1 6
#define GPR_ARG2 7
#define GPR_ARG3 8
#define GPR_ARG4 9
#define GPR_ARG5 10
#define GPR_RVAL0 3
#define GPR_RVAL1 4
#define GPR_RVAL GPR_RVAL0
#define NUM_GPRS 32
/* `system' registers. */
/* Note these are old v850 values, microblaze has many fewer */
#define SR_EIPC 0
#define SR_EIPSW 1
#define SR_FEPC 2
#define SR_FEPSW 3
#define SR_ECR 4
#define SR_PSW 5
#define SR_CTPC 16
#define SR_CTPSW 17
#define SR_DBPC 18
#define SR_DBPSW 19
#define SR_CTBP 20
#define SR_DIR 21
#define SR_ASID 23
#ifndef __ASSEMBLY__
typedef unsigned long microblaze_reg_t;
/* How processor state is stored on the stack during a syscall/signal.
If you change this structure, change the associated assembly-language
macros below too (PT_*)! */
struct pt_regs
{
/* General purpose registers. */
microblaze_reg_t gpr[NUM_GPRS];
microblaze_reg_t pc; /* program counter */
microblaze_reg_t psw; /* program status word */
microblaze_reg_t kernel_mode; /* 1 if in `kernel mode', 0 if user mode */
microblaze_reg_t single_step; /* 1 if in single step mode */
};
#define instruction_pointer(regs) ((regs)->pc)
#define user_mode(regs) (!(regs)->kernel_mode)
/* When a struct pt_regs is used to save user state for a system call in
the kernel, the system call is stored in the space for R0 (since it's
never used otherwise, R0 being a constant 0). Non-system-calls
simply store 0 there. */
#define PT_REGS_SYSCALL(regs) (regs)->gpr[0]
#define PT_REGS_SET_SYSCALL(regs, val) ((regs)->gpr[0] = (val))
#endif /* !__ASSEMBLY__ */
/* The number of bytes used to store each register. */
#define _PT_REG_SIZE 4
/* Offset of a general purpose register in a stuct pt_regs. */
#define PT_GPR(num) ((num) * _PT_REG_SIZE)
/* Offsets of various special registers & fields in a struct pt_regs. */
#define NUM_SPECIAL 4
#define PT_PC ((NUM_GPRS + 0) * _PT_REG_SIZE)
#define PT_PSW ((NUM_GPRS + 1) * _PT_REG_SIZE)
#define PT_KERNEL_MODE ((NUM_GPRS + 2) * _PT_REG_SIZE)
#define PT_SINGLESTEP ((NUM_GPRS + 3) * _PT_REG_SIZE)
#define PT_SYSCALL PT_GPR(0)
/* Size of struct pt_regs, including alignment. */
#define PT_SIZE ((NUM_GPRS + NUM_SPECIAL) * _PT_REG_SIZE)
/* These are `magic' values for PTRACE_PEEKUSR that return info about where
a process is located in memory. */
#define PT_TEXT_ADDR (PT_SIZE + 1)
#define PT_TEXT_LEN (PT_SIZE + 2)
#define PT_DATA_ADDR (PT_SIZE + 3)
#define PT_DATA_LEN (PT_SIZE + 4)
#endif /* __MICROBLAZE_PTRACE_H__ */

View File

@@ -0,0 +1,11 @@
/*
* Copyright (c) 2012 The Chromium OS Authors.
* SPDX-License-Identifier: GPL-2.0+
*/
#ifndef __ASM_MICROBLAZE_SECTIONS_H
#define __ASM_MICROBLAZE_SECTIONS_H
#include <asm-generic/sections.h>
#endif

View File

@@ -0,0 +1,16 @@
/*
* (C) Copyright 2013 - 2014 Xilinx, Inc
*
* Michal Simek <michal.simek@xilinx.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#ifndef _ASM_MICROBLAZE_SPL_H_
#define _ASM_MICROBLAZE_SPL_H_
#define BOOT_DEVICE_RAM 1
#define BOOT_DEVICE_NOR 2
#define BOOT_DEVICE_SPI 3
#endif

View File

@@ -0,0 +1,29 @@
/*
* include/asm-microblaze/string.h -- Architecture specific string routines
*
* Copyright (C) 2003 John Williams <jwilliams@itee.uq.edu.au>
* Copyright (C) 2001,2002 NEC Corporation
* Copyright (C) 2001,2002 Miles Bader <miles@gnu.org>
*
* This file is subject to the terms and conditions of the GNU General
* Public License. See the file COPYING in the main directory of this
* archive for more details.
*
* Written by Miles Bader <miles@gnu.org>
* Microblaze port by John Williams
*/
#ifndef __MICROBLAZE_STRING_H__
#define __MICROBLAZE_STRING_H__
#if 0
#define __HAVE_ARCH_MEMCPY
#define __HAVE_ARCH_MEMSET
#define __HAVE_ARCH_MEMMOVE
extern void *memcpy (void *, const void *, __kernel_size_t);
extern void *memset (void *, int, __kernel_size_t);
extern void *memmove (void *, const void *, __kernel_size_t);
#endif
#endif /* __MICROBLAZE_STRING_H__ */

View File

@@ -0,0 +1,161 @@
/*
* include/asm-microblaze/system.h -- Low-level interrupt/thread ops
*
* Copyright (C) 2003 John Williams (jwilliams@itee.uq.edu.au)
* based upon microblaze version
* Copyright (C) 2001 NEC Corporation
* Copyright (C) 2001 Miles Bader <miles@gnu.org>
*
* This file is subject to the terms and conditions of the GNU General
* Public License. See the file COPYING in the main directory of this
* archive for more details.
*
* Written by Miles Bader <miles@gnu.org>
* Microblaze port by John Williams
* Microblaze port by John Williams
*/
#ifndef __MICROBLAZE_SYSTEM_H__
#define __MICROBLAZE_SYSTEM_H__
#if 0
#include <linux/linkage.h>
#endif
#include <asm/ptrace.h>
#define prepare_to_switch() do { } while (0)
/*
* switch_to(n) should switch tasks to task ptr, first checking that
* ptr isn't the current task, in which case it does nothing.
*/
struct thread_struct;
extern void *switch_thread (struct thread_struct *last,
struct thread_struct *next);
#define switch_to(prev,next,last) do { \
if (prev != next) { \
(last) = switch_thread (&prev->thread, &next->thread); \
} \
} while (0)
/* Enable/disable interrupts. */
#define __sti() \
{ \
register unsigned tmp; \
__asm__ __volatile__ (" \
mfs %0, rmsr; \
ori %0, %0, 2; \
mts rmsr, %0" \
: "=r" (tmp) \
: \
: "memory"); \
}
#define __cli() \
{ \
register unsigned tmp; \
__asm__ __volatile__ (" \
mfs %0, rmsr; \
andi %0, %0, ~2; \
mts rmsr, %0" \
: "=r" (tmp) \
: \
: "memory"); \
}
#define __save_flags(flags) \
__asm__ __volatile__ ("mfs %0, rmsr" : "=r" (flags))
#define __restore_flags(flags) \
__asm__ __volatile__ ("mts rmsr, %0" :: "r" (flags))
#define __save_flags_cli(flags) \
{ \
register unsigned tmp; \
__asm__ __volatile__ (" \
mfs %0, rmsr; \
andi %1, %0, ~2; \
mts rmsr, %1;" \
: "=r" (flags), "=r" (tmp) \
: \
: "memory"); \
}
#define __save_flags_sti(flags) \
{ \
register unsigned tmp; \
__asm__ __volatile__ (" \
mfs %0, rmsr; \
ori %1, %0, 2; \
mts rmsr, %1;" \
: "=r" (flags) ,"=r" (tmp) \
: \
: "memory"); \
}
/* For spinlocks etc */
#define local_irq_save(flags) __save_flags_cli (flags)
#define local_irq_set(flags) __save_flags_sti (flags)
#define local_irq_restore(flags) __restore_flags (flags)
#define local_irq_disable() __cli ()
#define local_irq_enable() __sti ()
#define cli() __cli ()
#define sti() __sti ()
#define save_flags(flags) __save_flags (flags)
#define restore_flags(flags) __restore_flags (flags)
#define save_flags_cli(flags) __save_flags_cli (flags)
/*
* Force strict CPU ordering.
* Not really required on microblaze...
*/
#define nop() __asm__ __volatile__ ("nop")
#define mb() __asm__ __volatile__ ("nop" ::: "memory")
#define rmb() mb ()
#define wmb() mb ()
#define set_mb(var, value) do { var = value; mb(); } while (0)
#define set_wmb(var, value) do { var = value; wmb (); } while (0)
#ifdef CONFIG_SMP
#define smp_mb() mb ()
#define smp_rmb() rmb ()
#define smp_wmb() wmb ()
#else
#define smp_mb() barrier ()
#define smp_rmb() barrier ()
#define smp_wmb() barrier ()
#endif
#define xchg(ptr, with) \
((__typeof__ (*(ptr)))__xchg ((unsigned long)(with), (ptr), sizeof (*(ptr))))
#define tas(ptr) (xchg ((ptr), 1))
static inline unsigned long __xchg(unsigned long with,
__volatile__ void *ptr, int size)
{
unsigned long tmp, flags;
save_flags_cli (flags);
switch (size) {
case 1:
tmp = *(unsigned char *)ptr;
*(unsigned char *)ptr = with;
break;
case 2:
tmp = *(unsigned short *)ptr;
*(unsigned short *)ptr = with;
break;
case 4:
tmp = *(unsigned long *)ptr;
*(unsigned long *)ptr = with;
break;
}
restore_flags (flags);
return tmp;
}
#endif /* __MICROBLAZE_SYSTEM_H__ */

View File

@@ -0,0 +1,60 @@
#ifndef _ASM_TYPES_H
#define _ASM_TYPES_H
/*
* This file is never included by application software unless
* explicitly requested (e.g., via linux/types.h) in which case the
* application is Linux specific so (user-) name space pollution is
* not a major issue. However, for interoperability, libraries still
* need to be careful to avoid a name clashes.
*/
typedef unsigned short umode_t;
/*
* __xx is ok: it doesn't pollute the POSIX namespace. Use these in the
* header files exported to user space
*/
typedef __signed__ char __s8;
typedef unsigned char __u8;
typedef __signed__ short __s16;
typedef unsigned short __u16;
typedef __signed__ int __s32;
typedef unsigned int __u32;
#if defined(__GNUC__)
__extension__ typedef __signed__ long long __s64;
__extension__ typedef unsigned long long __u64;
#endif
/*
* These aren't exported outside the kernel to avoid name space clashes
*/
#ifdef __KERNEL__
typedef signed char s8;
typedef unsigned char u8;
typedef signed short s16;
typedef unsigned short u16;
typedef signed int s32;
typedef unsigned int u32;
typedef signed long long s64;
typedef unsigned long long u64;
#define BITS_PER_LONG 32
/* Dma addresses are 32-bits wide. */
typedef u32 dma_addr_t;
typedef unsigned long phys_addr_t;
typedef unsigned long phys_size_t;
#endif /* __KERNEL__ */
#endif /* _ASM_TYPES_H */

View File

@@ -0,0 +1,24 @@
/*
* (C) Copyright 2004 Atmark Techno, Inc.
*
* Yasushi SHOJI <yashi@atmark-techno.com>
*
* SPDX-License-Identifier: GPL-2.0+
*
********************************************************************
* NOTE: This header file defines an interface to U-Boot. Including
* this (unmodified) header file in another file is considered normal
* use of U-Boot, and does *not* fall under the heading of "derived
* work".
********************************************************************
*/
#ifndef _U_BOOT_H_
#define _U_BOOT_H_
#include <asm-generic/u-boot.h>
/* For image.h:image_check_target_arch() */
#define IH_ARCH_DEFAULT IH_ARCH_MICROBLAZE
#endif /* _U_BOOT_H_ */

View File

@@ -0,0 +1 @@
#include <asm-generic/unaligned.h>

View File

@@ -0,0 +1,9 @@
#
# (C) Copyright 2003-2006
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
#
# SPDX-License-Identifier: GPL-2.0+
#
obj-$(CONFIG_CMD_BOOTM) += bootm.o
obj-y += muldi3.o

View File

@@ -0,0 +1,86 @@
/*
* (C) Copyright 2007 Michal Simek
* (C) Copyright 2004 Atmark Techno, Inc.
*
* Michal SIMEK <monstr@monstr.eu>
* Yasushi SHOJI <yashi@atmark-techno.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <command.h>
#include <fdt_support.h>
#include <image.h>
#include <u-boot/zlib.h>
#include <asm/byteorder.h>
DECLARE_GLOBAL_DATA_PTR;
int do_bootm_linux(int flag, int argc, char * const argv[],
bootm_headers_t *images)
{
/* First parameter is mapped to $r5 for kernel boot args */
void (*thekernel) (char *, ulong, ulong);
char *commandline = getenv("bootargs");
ulong rd_data_start, rd_data_end;
/*
* allow the PREP bootm subcommand, it is required for bootm to work
*/
if (flag & BOOTM_STATE_OS_PREP)
return 0;
if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
return 1;
int ret;
char *of_flat_tree = NULL;
#if defined(CONFIG_OF_LIBFDT)
/* did generic code already find a device tree? */
if (images->ft_len)
of_flat_tree = images->ft_addr;
#endif
thekernel = (void (*)(char *, ulong, ulong))images->ep;
/* find ramdisk */
ret = boot_get_ramdisk(argc, argv, images, IH_ARCH_MICROBLAZE,
&rd_data_start, &rd_data_end);
if (ret)
return 1;
bootstage_mark(BOOTSTAGE_ID_RUN_OS);
if (!of_flat_tree && argc > 1)
of_flat_tree = (char *)simple_strtoul(argv[1], NULL, 16);
/* fixup the initrd now that we know where it should be */
if (images->rd_start && images->rd_end && of_flat_tree)
ret = fdt_initrd(of_flat_tree, images->rd_start,
images->rd_end);
if (ret)
return 1;
#ifdef DEBUG
printf("## Transferring control to Linux (at address 0x%08lx) ",
(ulong)thekernel);
printf("ramdisk 0x%08lx, FDT 0x%08lx...\n",
rd_data_start, (ulong) of_flat_tree);
#endif
#ifdef XILINX_USE_DCACHE
flush_cache(0, XILINX_DCACHE_BYTE_SIZE);
#endif
/*
* Linux Kernel Parameters (passing device tree):
* r5: pointer to command line
* r6: pointer to ramdisk
* r7: pointer to the fdt, followed by the board info data
*/
thekernel(commandline, rd_data_start, (ulong)of_flat_tree);
/* does not return */
return 1;
}

View File

@@ -0,0 +1,75 @@
/*
* U-Boot - muldi3.c contains routines for mult and div
*
*
* SPDX-License-Identifier: GPL-2.0+
*/
/* Generic function got from GNU gcc package, libgcc2.c */
#ifndef SI_TYPE_SIZE
#define SI_TYPE_SIZE 32
#endif
#define __ll_B (1L << (SI_TYPE_SIZE / 2))
#define __ll_lowpart(t) ((USItype) (t) % __ll_B)
#define __ll_highpart(t) ((USItype) (t) / __ll_B)
#define BITS_PER_UNIT 8
#if !defined(umul_ppmm)
#define umul_ppmm(w1, w0, u, v) \
do { \
USItype __x0, __x1, __x2, __x3; \
USItype __ul, __vl, __uh, __vh; \
\
__ul = __ll_lowpart(u); \
__uh = __ll_highpart(u); \
__vl = __ll_lowpart(v); \
__vh = __ll_highpart(v); \
\
__x0 = (USItype) __ul * __vl; \
__x1 = (USItype) __ul * __vh; \
__x2 = (USItype) __uh * __vl; \
__x3 = (USItype) __uh * __vh; \
\
__x1 += __ll_highpart(__x0); /* this can't give carry */\
__x1 += __x2; /* but this indeed can */ \
if (__x1 < __x2) /* did we get it? */ \
__x3 += __ll_B; /* yes, add it in the proper pos. */ \
\
(w1) = __x3 + __ll_highpart(__x1); \
(w0) = __ll_lowpart(__x1) * __ll_B + __ll_lowpart(__x0);\
} while (0)
#endif
#if !defined(__umulsidi3)
#define __umulsidi3(u, v) \
({DIunion __w; \
umul_ppmm(__w.s.high, __w.s.low, u, v); \
__w.ll; })
#endif
typedef unsigned int USItype __attribute__ ((mode(SI)));
typedef int SItype __attribute__ ((mode(SI)));
typedef int DItype __attribute__ ((mode(DI)));
typedef int word_type __attribute__ ((mode(__word__)));
struct DIstruct {
SItype low, high;
};
typedef union {
struct DIstruct s;
DItype ll;
} DIunion;
DItype __muldi3(DItype u, DItype v)
{
DIunion w;
DIunion uu, vv;
uu.ll = u, vv.ll = v;
/* panic("kernel panic for __muldi3"); */
w.ll = __umulsidi3(uu.s.low, vv.s.low);
w.s.high += ((USItype) uu.s.low * (USItype) vv.s.high
+ (USItype) uu.s.high * (USItype) vv.s.low);
return w.ll;
}