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,10 @@
#
# (C) Copyright 2003-2006
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
#
# SPDX-License-Identifier: GPL-2.0+
#
extra-y = start.o
obj-y = cpu_init.o serial.o cpu.o ambapp.o ambapp_low.o ambapp_low_c.o \
interrupts.o prom.o usb_uhci.o memcfg.o memcfg_low.o

View File

@@ -0,0 +1,316 @@
/* GRLIB AMBA Plug&Play information scanning, relies on assembler
* routines.
*
* (C) Copyright 2010, 2015
* Daniel Hellstrom, Cobham Gaisler, daniel@gaisler.com.
*
* SPDX-License-Identifier: GPL-2.0+
*/
/* #define DEBUG */
#include <common.h>
#include <malloc.h>
#include <ambapp.h>
#include <config.h>
/************ C INTERFACE OF ASSEMBLER SCAN ROUTINES ************/
struct ambapp_find_apb_info {
/* Address of APB device Plug&Play information */
struct ambapp_pnp_apb *pnp;
/* AHB Bus index of where the APB-Master Bridge device was found */
int ahb_bus_index;
int dec_index;
};
struct ambapp_find_ahb_info {
/* Address of AHB device Plug&Play information */
struct ambapp_pnp_ahb *pnp;
/* AHB Bus index of where the AHB device was found */
int ahb_bus_index;
int dec_index;
};
extern void ambapp_find_buses(unsigned int ioarea, struct ambapp_bus *abus);
extern int ambapp_find_apb(struct ambapp_bus *abus, unsigned int dev_vend,
int index, struct ambapp_find_apb_info *result);
extern int ambapp_find_ahb(struct ambapp_bus *abus, unsigned int dev_vend,
int index, int type, struct ambapp_find_ahb_info *result);
/************ C ROUTINES USED BY U-BOOT AMBA CORE DRIVERS ************/
struct ambapp_bus ambapp_plb __section(.data);
void ambapp_bus_init(
unsigned int ioarea,
unsigned int freq,
struct ambapp_bus *abus)
{
int i;
ambapp_find_buses(ioarea, abus);
for (i = 0; i < 6; i++)
if (abus->ioareas[i] == 0)
break;
abus->buses = i;
abus->freq = freq;
}
/* Parse APB PnP Information */
void ambapp_apb_parse(struct ambapp_find_apb_info *info, ambapp_apbdev *dev)
{
struct ambapp_pnp_apb *apb = info->pnp;
unsigned int apbbase = (unsigned int)apb & 0xfff00000;
dev->vendor = amba_vendor(apb->id);
dev->device = amba_device(apb->id);
dev->irq = amba_irq(apb->id);
dev->ver = amba_ver(apb->id);
dev->address = (apbbase | (((apb->iobar & 0xfff00000) >> 12))) &
(((apb->iobar & 0x0000fff0) << 4) | 0xfff00000);
dev->mask = amba_apb_mask(apb->iobar);
dev->ahb_bus_index = info->ahb_bus_index - 1;
}
/* Parse AHB PnP information */
void ambapp_ahb_parse(struct ambapp_find_ahb_info *info, ambapp_ahbdev *dev)
{
struct ambapp_pnp_ahb *ahb = info->pnp;
unsigned int ahbbase = (unsigned int)ahb & 0xfff00000;
int i, type;
unsigned int addr, mask, mbar;
dev->vendor = amba_vendor(ahb->id);
dev->device = amba_device(ahb->id);
dev->irq = amba_irq(ahb->id);
dev->ver = amba_ver(ahb->id);
dev->userdef[0] = ahb->custom[0];
dev->userdef[1] = ahb->custom[1];
dev->userdef[2] = ahb->custom[2];
dev->ahb_bus_index = info->ahb_bus_index - 1;
for (i = 0; i < 4; i++) {
mbar = ahb->mbar[i];
addr = amba_membar_start(mbar);
type = amba_membar_type(mbar);
if (type == AMBA_TYPE_AHBIO) {
addr = amba_ahbio_adr(addr, ahbbase);
mask = (((unsigned int)
(amba_membar_mask((~mbar))<<8)|0xff))+1;
} else {
/* AHB memory area, absolute address */
mask = (~((unsigned int)
(amba_membar_mask(mbar)<<20)))+1;
}
dev->address[i] = addr;
dev->mask[i] = mask;
dev->type[i] = type;
}
}
int ambapp_apb_find(struct ambapp_bus *abus, int vendor, int device,
int index, ambapp_apbdev *dev)
{
unsigned int devid = AMBA_PNP_ID(vendor, device);
int found;
struct ambapp_find_apb_info apbdev;
found = ambapp_find_apb(abus, devid, index, &apbdev);
if (found == 1)
ambapp_apb_parse(&apbdev, dev);
return found;
}
int ambapp_apb_count(struct ambapp_bus *abus, int vendor, int device)
{
unsigned int devid = AMBA_PNP_ID(vendor, device);
int found;
struct ambapp_find_apb_info apbdev;
found = ambapp_find_apb(abus, devid, 63, &apbdev);
if (found == 1)
return 64;
else
return 63 - apbdev.dec_index;
}
int ambapp_ahb_find(struct ambapp_bus *abus, int vendor, int device,
int index, ambapp_ahbdev *dev, int type)
{
int found;
struct ambapp_find_ahb_info ahbdev;
unsigned int devid = AMBA_PNP_ID(vendor, device);
found = ambapp_find_ahb(abus, devid, index, type, &ahbdev);
if (found == 1)
ambapp_ahb_parse(&ahbdev, dev);
return found;
}
int ambapp_ahbmst_find(struct ambapp_bus *abus, int vendor, int device,
int index, ambapp_ahbdev *dev)
{
return ambapp_ahb_find(abus, vendor, device, index, dev, DEV_AHB_MST);
}
int ambapp_ahbslv_find(struct ambapp_bus *abus, int vendor, int device,
int index, ambapp_ahbdev *dev)
{
return ambapp_ahb_find(abus, vendor, device, index, dev, DEV_AHB_SLV);
}
int ambapp_ahb_count(struct ambapp_bus *abus, int vendor, int device, int type)
{
int found;
struct ambapp_find_ahb_info ahbdev;
unsigned int devid = AMBA_PNP_ID(vendor, device);
found = ambapp_find_ahb(abus, devid, 63, type, &ahbdev);
if (found == 1)
return 64;
else
return 63 - ahbdev.dec_index;
}
int ambapp_ahbmst_count(struct ambapp_bus *abus, int vendor, int device)
{
return ambapp_ahb_count(abus, vendor, device, DEV_AHB_MST);
}
int ambapp_ahbslv_count(struct ambapp_bus *abus, int vendor, int device)
{
return ambapp_ahb_count(abus, vendor, device, DEV_AHB_SLV);
}
/* The define CONFIG_SYS_GRLIB_SINGLE_BUS may be defined on GRLIB systems
* where only one AHB Bus is available - no bridges are present. This option
* is available only to reduce the footprint.
*
* Defining this on a multi-bus GRLIB system may also work depending on the
* design.
*/
#ifndef CONFIG_SYS_GRLIB_SINGLE_BUS
/* GAISLER AHB2AHB Version 1 Bridge Definitions */
#define AHB2AHB_V1_FLAG_FFACT 0x0f0 /* Frequency factor against top bus */
#define AHB2AHB_V1_FLAG_FFACT_DIR 0x100 /* Factor direction, 0=down, 1=up */
#define AHB2AHB_V1_FLAG_MBUS 0x00c /* Master bus number mask */
#define AHB2AHB_V1_FLAG_SBUS 0x003 /* Slave bus number mask */
/* Get Parent bus frequency. Note that since we go from a "child" bus
* to a parent bus, the frequency factor direction is inverted.
*/
unsigned int gaisler_ahb2ahb_v1_freq(ambapp_ahbdev *ahb, unsigned int freq)
{
int dir;
unsigned char ffact;
/* Get division/multiple factor */
ffact = (ahb->userdef[0] & AHB2AHB_V1_FLAG_FFACT) >> 4;
if (ffact != 0) {
dir = ahb->userdef[0] & AHB2AHB_V1_FLAG_FFACT_DIR;
/* Calculate frequency by dividing or
* multiplying system frequency
*/
if (dir)
freq = freq * ffact;
else
freq = freq / ffact;
}
return freq;
}
/* AHB2AHB and L2CACHE ver 2 is not supported yet. */
unsigned int gaisler_ahb2ahb_v2_freq(ambapp_ahbdev *ahb, unsigned int freq)
{
panic("gaisler_ahb2ahb_v2_freq: AHB2AHB ver 2 not supported\n");
return -1;
}
#endif
/* Return the frequency of a AHB bus identified by index found
* note that this is not the AHB Bus number.
*/
unsigned int ambapp_bus_freq(struct ambapp_bus *abus, int ahb_bus_index)
{
unsigned int freq = abus->freq;
#ifndef CONFIG_SYS_GRLIB_SINGLE_BUS
unsigned int ioarea, ioarea_parent, bridge_pnp_ofs;
struct ambapp_find_ahb_info ahbinfo;
ambapp_ahbdev ahb;
int parent;
debug("ambapp_bus_freq: get freq on bus %d\n", ahb_bus_index);
while (ahb_bus_index != 0) {
debug(" BUS[0]: 0x%08x\n", abus->ioareas[0]);
debug(" BUS[1]: 0x%08x\n", abus->ioareas[1]);
debug(" BUS[2]: 0x%08x\n", abus->ioareas[2]);
debug(" BUS[3]: 0x%08x\n", abus->ioareas[3]);
debug(" BUS[4]: 0x%08x\n", abus->ioareas[4]);
debug(" BUS[5]: 0x%08x\n", abus->ioareas[5]);
/* Get I/O area of AHB bus */
ioarea = abus->ioareas[ahb_bus_index];
debug(" IOAREA: 0x%08x\n", ioarea);
/* Get parent bus */
parent = (ioarea & 0x7);
if (parent == 0) {
panic("%s: parent=0 indicates no parent! Stopping.\n",
__func__);
return -1;
}
parent = parent - 1;
bridge_pnp_ofs = ioarea & 0x7e0;
debug(" PARENT: %d\n", parent);
debug(" BRIDGE_OFS: 0x%08x\n", bridge_pnp_ofs);
/* Get AHB/AHB bridge PnP address */
ioarea_parent = (abus->ioareas[parent] & 0xfff00000) |
AMBA_CONF_AREA | AMBA_AHB_SLAVE_CONF_AREA;
ahbinfo.pnp = (struct ambapp_pnp_ahb *)
(ioarea_parent | bridge_pnp_ofs);
debug(" IOAREA PARENT: 0x%08x\n", ioarea_parent);
debug(" BRIDGE PNP: 0x%p\n", ahbinfo.pnp);
/* Parse the AHB information */
ahbinfo.ahb_bus_index = parent;
ambapp_ahb_parse(&ahbinfo, &ahb);
debug(" BRIDGE ID: VENDOR=%d(0x%x), DEVICE=%d(0x%x)\n",
ahb.vendor, ahb.vendor, ahb.device, ahb.device);
/* Different bridges may convert frequency differently */
if ((ahb.vendor == VENDOR_GAISLER) &&
((ahb.device == GAISLER_AHB2AHB) ||
(ahb.device == GAISLER_L2CACHE))) {
/* Get new frequency */
if (ahb.ver > 1)
freq = gaisler_ahb2ahb_v2_freq(&ahb, freq);
else
freq = gaisler_ahb2ahb_v1_freq(&ahb, freq);
debug(" NEW FREQ: %dHz\n", freq);
} else {
panic("%s: unsupported AMBA bridge\n", __func__);
return -1;
}
/* Step upwards towards system top bus */
ahb_bus_index = parent;
}
#endif
debug("ambapp_bus_freq: %dHz\n", freq);
return freq;
}

View File

@@ -0,0 +1,784 @@
/* GRLIB AMBA Plug&Play information scanning implemented without
* using memory (stack) and one register window. The code scan
* the PnP info and inserts the AHB bridges/buses into register
* i0-i5.
* The code support
* - up to 6 AHB buses
* - multiple APB buses
* - support for AHB2AHB & L2CACHE bridges
*
* (C) Copyright 2010, 2015
* Daniel Hellstrom, Cobham Gaisler, daniel@gaisler.com.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <ambapp.h>
.seg "text"
.globl _nomem_amba_init
.globl _nomem_ambapp_find_buses
.globl _nomem_find_apb
.globl _nomem_find_ahb
/* Overview
* ========
*
* _nomem_amba_init - Init AMBA bus and calls _nomem_ambapp_find_buses
* _nomem_ambapp_find_buses - Scan AMBA PnP info for AHB buses/bridges and
* place them in i0-i5, see below
* _nomem_find_apb - Find one APB device identified by VENDOR:DEVICE
* ID and an index.
* _nomem_find_ahb - Find one AHB Master or Slave device identified
* by VENDOR:DEVICE ID and an index.
* init_ahb_bridges - Local function. Clears i0-i5
* insert_ahb_bridge - Local function. Insert a new AHB bus into first
* free register in i0-i5. It also checks that the
* bus has not already been added.
* get_ahb_bridge - Local function. Get AHB bus from registers,
* return register iN, where N is defined by o0.
*
* The _nomem_find_apb and _nomem_find_ahb function requires that i0-i5
* are populated with the AHB buses of the system. The registers are
* initialized by _nomem_ambapp_find_buses.
*
* AHB Bus result and requirements of i0-i5
* ========================================
*
* i0: AHB BUS0 IOAREA, no parent bus
* i1: AHB BUS1 IOAREA, parent bus is always i0 (AHB BUS0) and bridge address
* i2: AHB BUS2 IOAREA, 3-bit parent bus number and bridge address
* i3: AHB BUS3 IOAREA, 3-bit parent bus number and bridge address
* i4: AHB BUS4 IOAREA, 3-bit parent bus number and bridge address
* i5: AHB BUS5 IOAREA, 3-bit parent bus number and bridge address
*
* AHB BUS
* -------
* Bits 31-20 (0xfff00000) contain the found bus I/O Area (AHB PnP area).
*
* 3-bit Parent bus
* ----------------
* Bits 2-0 (0x00000007) contain parent bus number. Zero if no parent
* bus, 1 = parent is AHB BUS 0 (i0), 2 = parent is AHB BUS 1 (i1)..
*
* Bridge Address
* --------------
* Bits 10-5 (0x000007e0) contain the index of the Bridge's PnP
* information on the parent. Since all bridges are found in the
* PnP information they all have a PnP entry. Together with the
* parent bus number the PnP entry can be found:
* PnPEntry = (BRIDGE_ADDRESS + (iN & 0xfff00000)) | 0x000ff800
* where N is the parent bus minus one.
*
*/
/* Function initializes the AHB Bridge I/O AREA storage. (Clears i0-i5)
*
* Arguments
* none
*
* Results
* none
*
* Clobbered
* none
*/
init_ahb_bridges:
mov %g0, %i0
mov %g0, %i1
mov %g0, %i2
mov %g0, %i3
mov %g0, %i4
retl
mov %g0, %i5
/* Function returns AHB Bridge I/O AREA for specified bus.
*
* Arguments
* - o0 = bus number
*
* Results
* - o0 = I/O AREA
*
* Clobbered
* none
*/
get_ahb_bridge:
cmp %o0, 1
be,a L1
mov %i0, %o0
cmp %o0, 2
be,a L1
mov %i1, %o0
cmp %o0, 3
be,a L1
mov %i2, %o0
cmp %o0, 4
be,a L1
mov %i3, %o0
cmp %o0, 5
be,a L1
mov %i4, %o0
cmp %o0, 6
be,a L1
mov %i5, %o0
/* o0 > 6: only 6 buses supported */
mov %g0, %o0
L1:
retl
nop
/* Function adds a AHB Bridge I/O AREA to the i0-i5 registers if
* not already added. It stores the bus PnP start information.
*
* Arguments
* - o0 = AHB Bridge I/O area
*
* Results
* none
*
* Clobbered
* o2, o3
*/
insert_ahb_bridge:
/* Check that bridge hasn't already been added */
andn %o0, 0x7ff, %o2
andn %i0, 0x7ff, %o3
cmp %o3, %o2
be L2
andn %i1, 0x7ff, %o3
cmp %o3, %o2
be L2
andn %i2, 0x7ff, %o3
cmp %o3, %o2
be L2
andn %i3, 0x7ff, %o3
cmp %o3, %o2
be L2
andn %i4, 0x7ff, %o3
cmp %o3, %o2
be L2
andn %i5, 0x7ff, %o3
cmp %o3, %o2
be L2
/* Insert into first free posistion */
cmp %i0, %g0
be,a L2
mov %o0, %i0
cmp %i1, %g0
be,a L2
mov %o0, %i1
cmp %i2, %g0
be,a L2
mov %o0, %i2
cmp %i3, %g0
be,a L2
mov %o0, %i3
cmp %i4, %g0
be,a L2
mov %o0, %i4
cmp %i5, %g0
be,a L2
mov %o0, %i5
L2:
retl
nop
/* FUNCTION int _nomem_find_ahb_bus(
* unsigned int bridge,
* int vendor_device,
* int index,
* void **pconf,
* int not_used,
* int option
* )
*
* Scans the AHB Master or Slave area for a matching VENDOR:DEVICE, the
* index is decremented when a matching device is found but index is
* greater than zero. When index is zero and a matching DEVICE:VENDOR
* is found the AHB configuration address and AHB I/O area is returned.
*
* i0-i7,l0,l1,l2,l3,l4,g2,o6 is not available for use.
* o1,o5 Must be left untouched
*
* Results
* - o0 Number of found devices (1 or 0)
* - o2 is decremented for each matching VENDOR:DEVICE found, zero if found
* - o3 Address of the AHB PnP configuration entry (Only valid if o0=1)
*
* Clobbered
* - o3 (Clobbered when no device was found)
* - o4 (Number of Devices left to search)
* - o0 (Bus ID, PnP ID, Device)
*/
_nomem_find_ahb_bus:
/* Get the number of Slaves/Masters.
* Only AHB Bus 0 has 64 AHB Masters/Slaves the
* other AHB buses has 16 slaves and 16 masters.
*/
add %g0, 16, %o4 /* Defaulting to 16 */
andcc %o0, 0x7, %g0 /* 3-bit bus id */
be,a .L_maxloops_detected
add %g0, 64, %o4 /* AHB Bus 0 has 64 AHB Masters/Slaves */
.L_maxloops_detected:
/* Get start address of AHB Slave or AHB Master area depending on what
* we are searching for.
*/
andn %o0, 0x7ff, %o0 /* Remove Bus ID and 5-bit AHB/AHB
* Bridge PnP Address to get I/O Area */
set AMBA_CONF_AREA, %o3
or %o3, %o0, %o3 /* Master area address */
cmp %o5, DEV_AHB_SLV
be,a .L_conf_area_calculated
or %o3, AMBA_AHB_SLAVE_CONF_AREA, %o3 /* Add 0x800 to get to slave area */
.L_conf_area_calculated:
/* Iterate over all AHB device and try to find matching DEVICE:VENDOR
* o1 - VENDOR|DEVICE
* o2 - Index
* o3 - Current AHB Device Configuration address
* o5 - Type (leave untouched)
*
* o4 - Number of AHB device left to process
* o0 - tmp
*/
.L_process_one_conf:
ld [%o3], %o0
andn %o0, 0xfff, %o0
cmp %o0, 0 /* No device if zero */
beq .L_next_conf
cmp %o1, 0 /* If VENDOR:DEVICE==0, consider all matching */
beq .L_process_ahb_dev_found
cmp %o0, %o1 /* Does VENDOR and DEVICE Match? */
bne .L_next_conf
nop
.L_process_ahb_dev_found:
/* Found a Matching VENDOR:DEVICE, index must also match */
cmp %o2, %g0
bne .L_next_conf
dec %o2
/* Index matches also, return happy with o3 set to AHB Conf Address */
mov %g0, %o2
retl
add %g0, 1, %o0
.L_next_conf:
subcc %o4, 1, %o4 /* One device has been processed,
* Are there more devices to process? */
bne .L_process_one_conf
add %o3, AMBA_AHB_CONF_LENGH, %o3 /* Next Configuration entry */
/* No Matching device found */
retl
mov %g0, %o0
/* FUNCTION int _nomem_find_ahb(
* int unused,
* int vendor_device,
* int index,
* void **pconf,
* int *ahb_bus_index,
* int option,
* )
*
* Find a AHB Master or AHB Slave device, it puts the address of the AHB PnP
* configuration in o3 (pconf), the I/O Area base address in o4 (pioarea).
*
* Calls _nomem_find_ahb_bus for every AHB bus.
*
* i0-i7, l0, l1, o6, g1, g4-g7 is not available for use.
*
* Arguments
* - o0 Unused
*
* Results
* - o0 Number of found devices (1 or 0)
* - o2 Decremented Index (Zero if found)
* - o3 Address of the AHB PnP configuration entry
* - o4 AHB Bus index the device was found on (if o0=1)
* - o5 Left untouched
*
* Clobbered
* - o0 (AHB Bridge and used by _nomem_find_ahb_bus)
* - o2 (index is decremented)
* - l2 (Current AHB Bus index)
* - g2 (return address)
*/
_nomem_find_ahb:
mov %o7, %g2 /* Save return address */
/* Scan all AHB Buses found for the AHB Master/Slave matching VENDOR:DEVICE */
clr %l2
.L_search_next_ahb_bus:
add %l2, 1, %l2
call get_ahb_bridge /* Get bus %l0 I/O Area */
mov %l2, %o0
cmp %o0, %g0
be .L_no_device_found /* If no more AHB bus is left to be scanned, proceed */
nop
call _nomem_find_ahb_bus /* Scan AHB bus %o0 for VENDOR:DEVICE. Index in o3 is decremented */
nop
cmp %o0, %g0 /* If VENDOR:DEVICE was not found scan next AHB Bus */
be .L_search_next_ahb_bus /* Do next bus is o0=0 (not found) */
nop
/* The device was found, o0 is 1 */
mov %g2, %o7 /* Restore return address */
retl
mov %l2, %o4 /* The AHB bus index the device was found on */
/* No device found matching */
.L_no_device_found:
mov %g2, %o7 /* Restore return address */
retl
mov %g0, %o0
/* FUNCTION int _nomem_find_apb_bus(
* int apbmst,
* int vendor_device,
* int index,
* void **pconf
* )
*
* Find a APB Slave device, it puts the address of the APB PnP configuration
* in o3 (pconf).
*
* Calls _nomem_find_ahb_bus for every AHB bus searching for AHB/APB Bridges.
* The AHB/APB bridges are AHB Slaves with ID GAISLER_APBMST.
*
* Results
* - o0 Number of found devices (1 or 0)
* - o2 Decremented Index
* - o3 Address of the found APB device PnP configuration entry
*
* Clobbered
* - o5 PnP VENDOR:DEVICE ID
*/
_nomem_find_apb_bus:
set AMBA_CONF_AREA, %o3
or %o0, %o3, %o3 /* Calc start of APB device PnP info */
add %g0, 16, %o0 /* o0, number of APB Slaves left to scan */
.L_process_one_apb_conf:
ld [%o3], %o5
andn %o5, 0xfff, %o5
cmp %o5, 0 /* No device if zero */
beq .L_process_apb_dev_not_found
cmp %o1, 0 /* If VENDOR:DEVICE == -1, consider all matching */
beq .L_process_apb_dev_found
cmp %o1, %o5 /* Found VENDOR:DEVICE */
bne .L_process_apb_dev_not_found
nop
.L_process_apb_dev_found:
/* Found matching device, compare index */
cmp %o2, %g0
bne .L_process_apb_dev_not_found
dec %o2
/* Matching index and VENDOR:DEVICE */
retl
add %g0, 1, %o0
.L_process_apb_dev_not_found:
subcc %o0, 1, %o0
bne .L_process_one_apb_conf
add %o3, 8, %o3
retl
mov %g0, %o0
/* FUNCTION int _nomem_find_apb(
* int unused,
* int vendor_device,
* int index,
* void **pconf,
* int *ahb_bus_index
* )
*
* Find a APB Slave device, it puts the address of the APB PnP configuration
* in o3 (pconf), the APB Master I/O Area base address in o4 (papbarea).
*
* Calls _nomem_find_ahb_bus for every AHB bus searching for AHB/APB Bridges.
* The AHB/APB bridges are AHB Slaves with ID GAISLER_APBMST.
*
* i0-i7, l0, l1, o6 is not available for use.
*
* Arguments
* - o0 Unused
*
* Results
* - o0 Number of found devices (1 or 0)
* - o2 Decremented Index if not found
* - o3 Address of the APB PnP configuration entry
* - o4 AHB Bus index of APB Bridge/APB Device
*
* Clobbered
* - o0 (AHB Bridge)
* - o2 (index is decremented)
* - l2 (APB DEV Index [7..4] : APBMST AHB Index [3..0])
* - l3 (Current AHB Bus index)
* - l4 (temporary storage for APB VENDOR:DEVICE)
* - o5 (AHB Slave ID)
* - o0 (clobbered by _nomem_find_ahb_bus)
* - g2 (Return address)
*/
_nomem_find_apb:
/* Scan all AHB Buses found for AHB/APB Bridges */
mov %o7, %g2 /* Save return address */
mov %o1, %l4 /* Save APB VENDOR:DEVICE */
sll %o2, 4, %l2 /* APB MST index = 0 */
add %g0, 1, %l3 /* AHB Bus index = 0 */
.L2_search_next_ahb_bus:
call get_ahb_bridge /* Get bus %l3 I/O Area */
mov %l3, %o0
cmp %o0, %g0
be .L2_no_device_found /* If no more AHB bus is left to be scanned, proceed */
add %g0, DEV_AHB_SLV, %o5 /* Search for AHB Slave */
sethi %hi(AMBA_PNP_ID(VENDOR_GAISLER, GAISLER_APBMST)), %o1
call _nomem_find_ahb_bus /* Scan AHB bus %o0 for VENDOR:DEVICE. Index in o3 is decremented */
and %l2, 0xf, %o2 /* Set APBMST index */
cmp %o0, %g0 /* If no AHB/APB Bridge was not found, scan next AHB Bus */
be .L_no_apb_bridge_found /* Do next bus */
nop
/* The AHB/APB Bridge was found.
* Search for the requested APB Device on the APB bus using
* find_apb_bus, it will decrement the index.
*/
ld [%o3 + AMBA_AHB_MBAR0_OFS], %o3
sll %o3, 16, %o0
and %o0, %o3, %o0 /* Address AND Address Mask */
sethi %hi(0xfff00000), %o3
and %o0, %o3, %o0 /* AHB/APB Bridge address */
srl %l2, 4, %o2 /* APB DEV Index */
call _nomem_find_apb_bus
mov %l4, %o1 /* APB VENDOR:DEVICE */
cmp %o0, %g0
be .L_apb_dev_not_found
mov %g2, %o7 /* Restore return address */
/* APB Device found
* o0 1
* o2 Index is decremented to zero
* o3 APB configuration address,
* o4 APB Bridge Configuration address.
*/
mov %g0, %o2
retl
mov %l3, %o4
.L_apb_dev_not_found:
/* Update APB DEV Index by saving output from find_apb_bus
* (index parameter) into bits [31..4] in L2.
*/
sll %o2, 4, %o2
and %l2, 0xf, %l2
or %o2, %l2, %l2
/* Try finding the next AHB/APB Bridge on the same AHB bus
* to find more APB devices
*/
ba .L2_search_next_ahb_bus /* Find next AHB/APB bridge */
inc %l2
.L_no_apb_bridge_found:
inc %l3 /* Next AHB Bus */
ba .L2_search_next_ahb_bus /* Process next AHB bus */
andn %l2, 0xf, %l2 /* Start at APB Bridge index 0 at every AHB Bus */
/* No device found matching */
.L2_no_device_found:
mov %g2, %o7 /* Restore return address */
srl %l2, 4, %o2 /* APB DEV Index */
retl
mov %g0, %o0
/* FUNCTION _nomem_amba_scan_gaisler_ahb2ahb_bridge(unsigned int bridge, int bus)
*
* Constraints:
* - o1 may not be used
* - o0, o2, o3 may be used.
*
* Arguments
* - o0 PnP Address of Bridge AHB device
* - o2 PnP ID of AHB device
*
* Results
* - o0 Address of new bus PnP area or a 1 if AHB device is no bridge
*
* Clobbered
* - o0, o2
*
*/
_nomem_amba_scan_gaisler_ahb2ahb_bridge:
andn %o2, 0xfff, %o2
sethi %hi(AMBA_PNP_ID(VENDOR_GAISLER,GAISLER_AHB2AHB)), %o3
cmp %o2, %o3
beq .L_is_ahb2ahb_bridge
nop
retl
add %g0, 1, %o0
.L_is_ahb2ahb_bridge:
/* Found a GAISLER AHB2AHB bridge */
retl
ld [%o0 + AMBA_AHB_CUSTOM1_OFS], %o0 /* Get address of bridge PnP area */
/* FUNCTION _nomem_amba_scan_gaisler_l2cache_bridge(unsigned int bridge, int bus)
*
* Constraints:
* - o1 may not be used
* - o0, o2, o3 may be used.
*
* Arguments
* - o0 PnP Address of Bridge AHB device
* - o2 PnP ID of AHB device
*
* Results
* - o0 Address of new bus PnP area or a 1 if AHB device is no bridge
*
* Clobbered
* - o0, o2
*
*/
_nomem_amba_scan_gaisler_l2cache_bridge:
andn %o2, 0xfff, %o2
sethi %hi(AMBA_PNP_ID(VENDOR_GAISLER,GAISLER_L2CACHE)), %o3
cmp %o2, %o3
beq .L_is_l2cache_bridge
nop
retl
add %g0, 1, %o0
.L_is_l2cache_bridge:
/* Found a GAISLER l2cache bridge */
retl
ld [%o0 + AMBA_AHB_CUSTOM1_OFS], %o0 /* Get address of bridge PnP area */
/* FUNCTION _nomem_amba_scan(unsigned int bridge, int bus)
*
* Constraints:
* i0-i7, l0 is used by caller
* o5-o7 may not be used.
*
* Arguments
* - o0 Bridge Information: I/O AREA and parent bus
* - o1 Bus
*
* Results
* - o0 Number of AHB bridges found
*
* Clobbered
* - o0 (Current AHB slave conf address)
* - o2 (Used by insert_bridge)
* - o3 (Used by insert_bridge)
* - l1 (Number of AHB Slaves left to process)
* - l2 (Current AHB slave conf address)
* - g2 (Return address)
*/
_nomem_amba_scan:
mov %o7, %g2 /* Save return address */
set 16, %l1
cmp %o1, 1
be,a .L2_maxloops_detected
add %g0, 64, %l1
.L2_maxloops_detected:
/* Clear 3-bit parent bus from bridge to get I/O AREA, then or
* (AMBA_CONF_AREA | AMBA_AHB_SLAVE_CONF_AREA) to get first AHB slave
* conf address.
*/
andn %o0, 0x7ff, %o0
set (AMBA_CONF_AREA | AMBA_AHB_SLAVE_CONF_AREA), %l2
or %o0, %l2, %l2
/* Scan AHB Slave area for AHB<->AHB bridges. For each AHB device
* all "bridge drivers" are called, the driver function interface:
*
* Input:
* - o0 PnP Address of Bridge AHB device
* - o2 PnP ID of AHB device
* Return values:
* - o0 Address of new bus PnP area, returning a 1 in o2 means not found
*
* Constraints:
* - o1 may not be used
* - o0, o2, o3 may be used.
*
*/
.L_scan_one_ahb_slave:
ld [%l2], %o2
cmp %o2, %g0
beq .L_scan_next_ahb_slave
nop
/* Call the GAISLER AHB2AHB bridge driver */
call _nomem_amba_scan_gaisler_ahb2ahb_bridge
mov %l2, %o0
cmp %o0, 1
bne .L_found_bridge
ld [%l2], %o2
/* Call the GAISLER L2CACHE bridge driver */
call _nomem_amba_scan_gaisler_l2cache_bridge
mov %l2, %o0
cmp %o0, 1
bne .L_found_bridge
ld [%l2], %o2
/* Insert next bridge "driver" function here */
/* The PnP ID did not match a bridge - a new bus was not found ==>
* step to next AHB device */
ba .L_scan_next_ahb_slave
nop
/* Add Found bus */
.L_found_bridge:
and %l2, 0x7e0, %o2
or %o2, %o0, %o0 /* Add AHB/AHB Bridge PnP address */
call insert_ahb_bridge /* Insert Bridge into found buses storage */
or %o1, %o0, %o0 /* Add parent bus LSB 3-bits */
.L_scan_next_ahb_slave:
/* More Slaves to process? */
subcc %l1, 1, %l1
bne .L_scan_one_ahb_slave
add %l2, AMBA_AHB_CONF_LENGH, %l2
/* No more AHB devices to process */
mov %g2, %o7 /* Restore return address */
retl
nop
/* FUNCTION _nomem_ambapp_find_buses(unsigned int ioarea)
*
* Find AMBA AHB buses.
*
* Constraints:
* i6-i7, l7 is used by caller
*
* Arguments
* - o0 Bridge Information: I/O AREA and parent bus
*
* Results
* - o0 Number of AHB bridges found
* - i0-i5 initialized
*
* Clobbered
* - o0 (Current AHB slave conf address)
* - o2 (Used by insert_bridge)
* - o3 (Used by insert_bridge)
* - l0 (Current AHB Bus)
* - l1 (Used by nomem_amba_scan)
* - l2 (Used by nomem_amba_scan)
* - l3 (Used by nomem_amba_scan)
* - l4 (Used by nomem_amba_scan)
*
* - g1 (level 1 return address)
* - g2 (Used by nomem_amba_scan)
*/
_nomem_ambapp_find_buses:
mov %o7, %g1 /* Save return address */
/* Initialize AHB Bus storage */
call init_ahb_bridges
nop
/* Insert AHB Bus 0 */
call insert_ahb_bridge
nop /* Argument already prepared by caller */
/* Scan AHB Bus 0 for AHB Bridges */
call _nomem_amba_scan
add %g0, 1, %o1
/* Scan all AHB Buses found for more AHB Bridges */
add %g0, 2, %l0
.L100_search_next_ahb_bus:
call get_ahb_bridge /* Get bus %l0 I/O Area */
mov %l0, %o0
cmp %o0, %g0
be .L100_return /* If no more AHB bus is left to be scanned, proceed */
nop
call _nomem_amba_scan /* Scan bus %l0 for AHB Bridges. i0-i7,l0 is used */
mov %l0, %o1 /* I/O AREA untouched in o0 */
ba .L100_search_next_ahb_bus /* Do next bus */
add %l0, 1, %l0
.L100_return:
mov %g1, %o7
retl
nop
/* FUNCTION _nomem_amba_init(unsigned int ioarea)
*
* Find all AHB buses
*
* Constraints:
* i6, i7, o6, o7, l7, l6, g3, g4, g5, g6, g7 is used by caller
*
* Arguments
* - o0 Bridge Information: I/O AREA and parent bus
*
* Results
* - o0 Number of AHB bridges found
*
* Clobbered
* - l0, l1, l2, l3, l4, g1, g2 (used by _nomem_ambapp_find_buses)
* - o0, o1, o2, o3 (Used as arguments)
* - o5 (return address)
* - g1 (level 1 return address)
* - g2 (level 2 return address)
*/
_nomem_amba_init:
mov %o7, %o5 /* Save return address, o5 not used */
/* Scan for buses, it will init i0-i5 */
call _nomem_ambapp_find_buses
nop
mov %o5, %o7
retl
nop
/* Call tree and their return address register
*
*_nomem_amba_scan (g1)
* -> init_ahb_bridges (o7)
* -> insert_ahb_bridge (o7)
* -> _nomem_amba_scan (g2)
* -> insert_ahb_bridge (o7)
* -> get_ahb_bridge (o7)
*
*
* -> _nomem_find_apb (g2)
* -> get_ahb_bridge (o7)
* -> _nomem_find_ahb_bus (o7)
* -> _nomem_find_apb_bus (o7)
* -> _nomem_find_ahb (g2)
* -> get_ahb_bridge (o7)
* -> _nomem_find_ahb_bus (o7)
* -> mem_handler.func() (o7)
*
*/

View File

@@ -0,0 +1,113 @@
/* C-interface for AMBA PnP scanning functions implemented in
* ambapp_low.S. At the point the memory and stack can be
* used.
*
* (C) Copyright 2010, 2015
* Daniel Hellstrom, Cobham Gaisler, daniel@gaisler.com.
*
* SPDX-License-Identifier: GPL-2.0+
*/
.seg "text"
.extern _nomem_ambapp_find_buses
.extern _nomem_find_apb
.extern _nomem_find_ahb
.globl ambapp_find_buses
.globl ambapp_find_apb
.globl ambapp_find_ahb
/* C-interface for _nomem_ambapp_find_buses used when memory is available.
*/
ambapp_find_buses:
save %sp, -104, %sp
mov %i1, %l7 /* Save second argument */
call _nomem_ambapp_find_buses
mov %i0, %o0
/* Store result */
st %g0, [%l7+0x00]
st %i0, [%l7+0x04]
st %i1, [%l7+0x08]
st %i2, [%l7+0x0c]
st %i3, [%l7+0x10]
st %i4, [%l7+0x14]
st %i5, [%l7+0x18]
ret
restore
/* C-interface for _nomem_find_apb used when memory is available.
*
* void ambapp_find_apb(
* struct ambapp_bus *abus,
* unsigned int dev_vend,
* int index,
* struct ambapp_find_apb_info *result
* );
*
*/
ambapp_find_apb:
save %sp, -104, %sp
mov %i3, %l7 /* Save second argument */
mov %i1, %o1
mov %i2, %o2
/* Initialize buses available in system */
ld [%i0+0x08], %i1
ld [%i0+0x0c], %i2
ld [%i0+0x10], %i3
ld [%i0+0x14], %i4
ld [%i0+0x18], %i5
call _nomem_find_apb
ld [%i0+0x04], %i0
st %o2, [%l7+0x08] /* Decremented Index */
st %o3, [%l7] /* PnP configuration address of APB Device */
st %o4, [%l7+0x04] /* AHB Bus Index of AHB/APB bridge and APB Device */
mov %o0, %i0
ret
restore
/* C-interface for _nomem_find_ahb used when memory is available.
*
* void ambapp_find_ahb(
* struct ambapp_bus *abus,
* unsigned int dev_vend,
* int index,
* int type,
* struct ambapp_find_ahb_info *result
* );
*
*/
ambapp_find_ahb:
save %sp, -104, %sp
mov %i4, %l7 /* Save second argument */
clr %o0
mov %i1, %o1
mov %i2, %o2
clr %o3
clr %o4
mov %i3, %o5
/* Initialize buses available in system */
ld [%i0+0x08], %i1
ld [%i0+0x0c], %i2
ld [%i0+0x10], %i3
ld [%i0+0x14], %i4
ld [%i0+0x18], %i5
call _nomem_find_ahb
ld [%i0+0x04], %i0
st %o2, [%l7+0x08] /* Decremented Index */
st %o3, [%l7] /* PnP configuration address of AHB Device */
st %o4, [%l7+0x04] /* AHB Bus Index of AHB Device */
mov %o0, %i0
ret
restore

View File

@@ -0,0 +1,113 @@
/* CPU specific code for the LEON3 CPU
*
* (C) Copyright 2007, 2015
* Daniel Hellstrom, Cobham Gaisler, daniel@gaisler.com
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <watchdog.h>
#include <command.h>
#include <netdev.h>
#include <asm/io.h>
#include <asm/processor.h>
#include <ambapp.h>
DECLARE_GLOBAL_DATA_PTR;
extern void _reset_reloc(void);
int leon_cpu_cnt = 1;
int leon_ver = 3;
unsigned int leon_cpu_freq = CONFIG_SYS_CLK_FREQ;
int cpu_freq(void)
{
ambapp_ahbdev dev;
if (leon_ver == 3) {
ambapp_ahbmst_find(&ambapp_plb, VENDOR_GAISLER,
GAISLER_LEON3, 0, &dev);
} else {
ambapp_ahbmst_find(&ambapp_plb, VENDOR_GAISLER,
GAISLER_LEON4, 0, &dev);
}
leon_cpu_freq = ambapp_bus_freq(&ambapp_plb, dev.ahb_bus_index);
return 0;
}
int checkcpu(void)
{
int cnt;
char str[4];
/* check LEON version here */
cnt = ambapp_ahbmst_count(&ambapp_plb, VENDOR_GAISLER, GAISLER_LEON3);
if (cnt <= 0) {
cnt = ambapp_ahbmst_count(&ambapp_plb, VENDOR_GAISLER,
GAISLER_LEON4);
if (cnt > 0)
leon_ver = 4;
}
cpu_freq();
str[0] = '\0';
if (cnt > 1) {
leon_cpu_cnt = cnt;
str[0] = '0' + cnt;
str[1] = 'x';
str[2] = '\0';
}
printf("CPU: %sLEON%d @ %dMHz\n", str, leon_ver,
leon_cpu_freq / 1000000);
return 0;
}
#ifdef CONFIG_DISPLAY_CPUINFO
int print_cpuinfo(void)
{
printf("CPU: LEON3\n");
return 0;
}
#endif
/* ------------------------------------------------------------------------- */
void cpu_reset(void)
{
/* Interrupts off */
disable_interrupts();
/* jump to restart in flash */
_reset_reloc();
}
int do_reset(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
{
cpu_reset();
return 1;
}
u64 flash_read64(void *addr)
{
return __raw_readq(addr);
}
/* ------------------------------------------------------------------------- */
#ifdef CONFIG_GRETH
int cpu_eth_init(bd_t *bis)
{
return greth_initialize(bis);
}
#endif

View File

@@ -0,0 +1,175 @@
/* Initializes CPU and basic hardware such as memory
* controllers, IRQ controller and system timer 0.
*
* (C) Copyright 2007, 2015
* Daniel Hellstrom, Cobham Gaisler, daniel@gaisler.com
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <asm/asi.h>
#include <asm/leon.h>
#include <asm/io.h>
#include <ambapp.h>
#include <grlib/irqmp.h>
#include <grlib/gptimer.h>
#include <debug_uart.h>
#include <config.h>
/* Default Plug&Play I/O area */
#ifndef CONFIG_AMBAPP_IOAREA
#define CONFIG_AMBAPP_IOAREA AMBA_DEFAULT_IOAREA
#endif
/* Select which TIMER that will become the time base */
#ifndef CONFIG_SYS_GRLIB_GPTIMER_INDEX
#define CONFIG_SYS_GRLIB_GPTIMER_INDEX 0
#endif
DECLARE_GLOBAL_DATA_PTR;
ambapp_dev_irqmp *irqmp = NULL;
/*
* Breath some life into the CPU...
*
* Run from FLASH/PROM:
* - until memory controller is set up, only registers available
* - memory controller has already been setup up, stack can be used
* - no global variables available for writing
* - constants available
*/
void cpu_init_f(void)
{
#ifdef CONFIG_DEBUG_UART
debug_uart_init();
#endif
}
/* If cache snooping is available in hardware the result will be set
* to 0x800000, otherwise 0.
*/
static unsigned int snoop_detect(void)
{
unsigned int result;
asm("lda [%%g0] 2, %0" : "=r"(result));
return result & 0x00800000;
}
int arch_cpu_init(void)
{
ambapp_apbdev apbdev;
int index;
gd->cpu_clk = CONFIG_SYS_CLK_FREQ;
gd->bus_clk = CONFIG_SYS_CLK_FREQ;
gd->ram_size = CONFIG_SYS_SDRAM_SIZE;
gd->arch.snooping_available = snoop_detect();
/* Initialize the AMBA Plug & Play bus structure, the bus
* structure represents the AMBA bus that the CPU is located at.
*/
ambapp_bus_init(CONFIG_AMBAPP_IOAREA, CONFIG_SYS_CLK_FREQ, &ambapp_plb);
/* Initialize/clear all the timers in the system.
*/
for (index = 0; ambapp_apb_find(&ambapp_plb, VENDOR_GAISLER,
GAISLER_GPTIMER, index, &apbdev) == 1; index++) {
ambapp_dev_gptimer *timer;
unsigned int bus_freq;
int i, ntimers;
timer = (ambapp_dev_gptimer *)apbdev.address;
/* Different buses may have different frequency, the
* frequency of the bus tell in which frequency the timer
* prescaler operates.
*/
bus_freq = ambapp_bus_freq(&ambapp_plb, apbdev.ahb_bus_index);
/* Initialize prescaler common to all timers to 1MHz */
timer->scalar = timer->scalar_reload =
(((bus_freq / 1000) + 500) / 1000) - 1;
/* Clear all timers */
ntimers = timer->config & 0x7;
for (i = 0; i < ntimers; i++) {
timer->e[i].ctrl = GPTIMER_CTRL_IP;
timer->e[i].rld = 0;
timer->e[i].ctrl = GPTIMER_CTRL_LD;
}
}
return 0;
}
/*
* initialize higher level parts of CPU like time base and timers
*/
int cpu_init_r(void)
{
ambapp_apbdev apbdev;
int cpu;
/*
* Find AMBA APB IRQMP Controller,
*/
if (ambapp_apb_find(&ambapp_plb, VENDOR_GAISLER,
GAISLER_IRQMP, 0, &apbdev) != 1) {
panic("%s: IRQ controller not found\n", __func__);
return -1;
}
irqmp = (ambapp_dev_irqmp *)apbdev.address;
/* initialize the IRQMP */
irqmp->ilevel = 0xf; /* all IRQ off */
irqmp->iforce = 0;
irqmp->ipend = 0;
irqmp->iclear = 0xfffe; /* clear all old pending interrupts */
for (cpu = 0; cpu < 16; cpu++) {
/* mask and clear force for all IRQs on CPU[N] */
irqmp->cpu_mask[cpu] = 0;
irqmp->cpu_force[cpu] = 0;
}
return 0;
}
;
int timer_init(void)
{
ambapp_dev_gptimer_element *tmr;
ambapp_dev_gptimer *gptimer;
ambapp_apbdev apbdev;
unsigned bus_freq;
if (ambapp_apb_find(&ambapp_plb, VENDOR_GAISLER, GAISLER_GPTIMER,
CONFIG_SYS_GRLIB_GPTIMER_INDEX, &apbdev) != 1) {
panic("%s: gptimer not found!\n", __func__);
return -1;
}
gptimer = (ambapp_dev_gptimer *) apbdev.address;
/* Different buses may have different frequency, the
* frequency of the bus tell in which frequency the timer
* prescaler operates.
*/
bus_freq = ambapp_bus_freq(&ambapp_plb, apbdev.ahb_bus_index);
/* initialize prescaler common to all timers to 1MHz */
gptimer->scalar = gptimer->scalar_reload =
(((bus_freq / 1000) + 500) / 1000) - 1;
tmr = (ambapp_dev_gptimer_element *)&gptimer->e[0];
tmr->val = 0;
tmr->rld = ~0;
tmr->ctrl = GPTIMER_CTRL_EN | GPTIMER_CTRL_RS | GPTIMER_CTRL_LD;
CONFIG_SYS_TIMER_COUNTER = (void *)&tmr->val;
return 0;
}

View File

@@ -0,0 +1,193 @@
/*
* (C) Copyright 2007
* Daniel Hellstrom, Gaisler Research, daniel@gaisler.com
*
* (C) Copyright 2006
* Detlev Zundel, DENX Software Engineering, dzu@denx.de
*
* (C) Copyright -2003
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
* (C) Copyright 2001
* Josh Huber <huber@mclx.com>, Mission Critical Linux, Inc.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <asm/stack.h>
#include <common.h>
#include <asm/io.h>
#include <asm/processor.h>
#include <command.h>
#include <asm/irq.h>
#include <asm/leon.h>
#include <ambapp.h>
#include <grlib/irqmp.h>
#include <grlib/gptimer.h>
/* 15 normal irqs and a non maskable interrupt */
#define NR_IRQS 15
struct irq_action {
interrupt_handler_t *handler;
void *arg;
unsigned int count;
};
extern ambapp_dev_irqmp *irqmp;
extern ambapp_dev_gptimer *gptimer;
static struct irq_action irq_handlers[NR_IRQS] = { {0}, };
static int spurious_irq_cnt = 0;
static int spurious_irq = 0;
static inline unsigned int irqmp_get_irqmask(unsigned int irq)
{
if ((irq < 0) || (irq >= NR_IRQS)) {
return 0;
} else {
return (1 << irq);
}
}
static void leon3_ic_disable(unsigned int irq)
{
unsigned int mask, pil;
if (!irqmp)
return;
pil = intLock();
/* get mask of interrupt */
mask = irqmp_get_irqmask(irq);
/* set int level */
irqmp->cpu_mask[0] = SPARC_NOCACHE_READ(&irqmp->cpu_mask[0]) & (~mask);
intUnlock(pil);
}
static void leon3_ic_enable(unsigned int irq)
{
unsigned int mask, pil;
if (!irqmp)
return;
pil = intLock();
/* get mask of interrupt */
mask = irqmp_get_irqmask(irq);
/* set int level */
irqmp->cpu_mask[0] = SPARC_NOCACHE_READ(&irqmp->cpu_mask[0]) | mask;
intUnlock(pil);
}
void handler_irq(int irq, struct pt_regs *regs)
{
if (irq_handlers[irq].handler) {
if (((unsigned int)irq_handlers[irq].handler > CONFIG_SYS_RAM_END) ||
((unsigned int)irq_handlers[irq].handler < CONFIG_SYS_RAM_BASE)
) {
printf("handler_irq: bad handler: %x, irq number %d\n",
(unsigned int)irq_handlers[irq].handler, irq);
return;
}
irq_handlers[irq].handler(irq_handlers[irq].arg);
irq_handlers[irq].count++;
} else {
spurious_irq_cnt++;
spurious_irq = irq;
}
}
void leon3_force_int(int irq)
{
if (!irqmp || (irq >= NR_IRQS) || (irq < 0))
return;
printf("Forcing interrupt %d\n", irq);
irqmp->iforce = SPARC_NOCACHE_READ(&irqmp->iforce) | (1 << irq);
}
/****************************************************************************/
int interrupt_init_cpu(void)
{
return (0);
}
/****************************************************************************/
/*
* Install and free a interrupt handler.
*/
void irq_install_handler(int irq, interrupt_handler_t * handler, void *arg)
{
if (irq < 0 || irq >= NR_IRQS) {
printf("irq_install_handler: bad irq number %d\n", irq);
return;
}
if (irq_handlers[irq].handler != NULL)
printf("irq_install_handler: 0x%08lx replacing 0x%08lx\n",
(ulong) handler, (ulong) irq_handlers[irq].handler);
if (((unsigned int)handler > CONFIG_SYS_RAM_END) ||
((unsigned int)handler < CONFIG_SYS_RAM_BASE)
) {
printf("irq_install_handler: bad handler: %x, irq number %d\n",
(unsigned int)handler, irq);
return;
}
irq_handlers[irq].handler = handler;
irq_handlers[irq].arg = arg;
/* enable irq on IRQMP hardware */
leon3_ic_enable(irq);
}
void irq_free_handler(int irq)
{
if (irq < 0 || irq >= NR_IRQS) {
printf("irq_free_handler: bad irq number %d\n", irq);
return;
}
/* disable irq on IRQMP hardware */
leon3_ic_disable(irq);
irq_handlers[irq].handler = NULL;
irq_handlers[irq].arg = NULL;
}
/****************************************************************************/
#if defined(CONFIG_CMD_IRQ)
void do_irqinfo(cmd_tbl_t * cmdtp, bd_t * bd, int flag, int argc, char * const argv[])
{
int irq;
unsigned int pil = get_pil();
printf("PIL level: %u\n\r", pil);
printf("Spurious IRQ: %u, last unknown IRQ: %d\n",
spurious_irq_cnt, spurious_irq);
puts("\nInterrupt-Information:\n" "Nr Routine Arg Count\n");
for (irq = 0; irq < NR_IRQS; irq++) {
if (irq_handlers[irq].handler != NULL) {
printf("%02d %p %p %d\n", irq,
irq_handlers[irq].handler,
irq_handlers[irq].arg,
irq_handlers[irq].count);
}
}
}
#endif

View File

@@ -0,0 +1,237 @@
/* GRLIB Memory controller setup. The register values are used
* from the associated low level assembler routine implemented
* in memcfg_low.S.
*
* (C) Copyright 2010, 2015
* Daniel Hellstrom, Cobham Gaisler, daniel@gaisler.com.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <ambapp.h>
#include "memcfg.h"
#include <config.h>
#ifdef CONFIG_SYS_GRLIB_ESA_MCTRL1
struct mctrl_setup esa_mctrl1_cfg = {
.reg_mask = 0x7,
.regs = {
{
.mask = 0x00000300,
.value = CONFIG_SYS_GRLIB_ESA_MCTRL1_CFG1,
},
{
.mask = 0x00000000,
.value = CONFIG_SYS_GRLIB_ESA_MCTRL1_CFG2,
},
{
.mask = 0x00000000,
.value = CONFIG_SYS_GRLIB_ESA_MCTRL1_CFG3,
},
}
};
#ifdef CONFIG_SYS_GRLIB_ESA_MCTRL2
struct mctrl_setup esa_mctrl2_cfg = {
.reg_mask = 0x7,
.regs = {
{
.mask = 0x00000300,
.value = CONFIG_SYS_GRLIB_ESA_MCTRL2_CFG1,
},
{
.mask = 0x00000000,
.value = CONFIG_SYS_GRLIB_ESA_MCTRL2_CFG2,
},
{
.mask = 0x00000000,
.value = CONFIG_SYS_GRLIB_ESA_MCTRL2_CFG3,
},
}
};
#endif
#endif
#ifdef CONFIG_SYS_GRLIB_GAISLER_FTMCTRL1
struct mctrl_setup gaisler_ftmctrl1_cfg = {
.reg_mask = 0x7,
.regs = {
{
.mask = 0x00000300,
.value = CONFIG_SYS_GRLIB_GAISLER_FTMCTRL1_CFG1,
},
{
.mask = 0x00000000,
.value = CONFIG_SYS_GRLIB_GAISLER_FTMCTRL1_CFG2,
},
{
.mask = 0x00000000,
.value = CONFIG_SYS_GRLIB_GAISLER_FTMCTRL1_CFG3,
},
}
};
#ifdef CONFIG_SYS_GRLIB_GAISLER_FTMCTRL2
struct mctrl_setup gaisler_ftmctrl2_cfg = {
.reg_mask = 0x7,
.regs = {
{
.mask = 0x00000300,
.value = CONFIG_SYS_GRLIB_GAISLER_FTMCTRL2_CFG1,
},
{
.mask = 0x00000000,
.value = CONFIG_SYS_GRLIB_GAISLER_FTMCTRL2_CFG2,
},
{
.mask = 0x00000000,
.value = CONFIG_SYS_GRLIB_GAISLER_FTMCTRL2_CFG3,
},
}
};
#endif
#endif
#ifdef CONFIG_SYS_GRLIB_GAISLER_SDCTRL1
struct mctrl_setup gaisler_sdctrl1_cfg = {
.reg_mask = 0x1,
.regs = {
{
.mask = 0x00000000,
.value = CONFIG_SYS_GRLIB_GAISLER_SDCTRL1_CTRL,
},
}
};
#ifdef CONFIG_SYS_GRLIB_GAISLER_SDCTRL2
struct mctrl_setup gaisler_sdctrl2_cfg = {
.reg_mask = 0x1,
.regs = {
{
.mask = 0x00000000,
.value = CONFIG_SYS_GRLIB_GAISLER_SDCTRL2_CTRL,
},
}
};
#endif
#endif
#ifdef CONFIG_SYS_GRLIB_GAISLER_DDR2SPA1
struct ahbmctrl_setup gaisler_ddr2spa1_cfg = {
.ahb_mbar_no = 1,
.reg_mask = 0xd,
.regs = {
{
.mask = 0x00000000,
.value = CONFIG_SYS_GRLIB_GAISLER_DDR2SPA1_CFG1,
},
{ 0x00000000, 0},
{
.mask = 0x00000000,
.value = CONFIG_SYS_GRLIB_GAISLER_DDR2SPA1_CFG3,
},
{
.mask = 0x00000000,
.value = CONFIG_SYS_GRLIB_GAISLER_DDR2SPA1_CFG4,
},
}
};
#ifdef CONFIG_SYS_GRLIB_GAISLER_DDR2SPA2
struct ahbmctrl_setup gaisler_ddr2spa2_cfg = {
.ahb_mbar_no = 1,
.reg_mask = 0xd,
.regs = {
{
.mask = 0x00000000,
.value = CONFIG_SYS_GRLIB_GAISLER_DDR2SPA2_CFG1,
},
{ 0x00000000, 0},
{
.mask = 0x00000000,
.value = CONFIG_SYS_GRLIB_GAISLER_DDR2SPA2_CFG3,
},
{
.mask = 0x00000000,
.value = CONFIG_SYS_GRLIB_GAISLER_DDR2SPA2_CFG4,
},
}
};
#endif
#endif
#ifdef CONFIG_SYS_GRLIB_GAISLER_DDRSPA1
struct ahbmctrl_setup gaisler_ddrspa1_cfg = {
.ahb_mbar_no = 1,
.reg_mask = 0x1,
.regs = {
{
.mask = 0x00000000,
.value = CONFIG_SYS_GRLIB_GAISLER_DDRSPA1_CTRL,
},
}
};
#ifdef CONFIG_SYS_GRLIB_GAISLER_DDRSPA2
struct ahbmctrl_setup gaisler_ddrspa2_cfg = {
.ahb_mbar_no = 1,
.reg_mask = 0x1,
.regs = {
{
.mask = 0x00000000,
.value = CONFIG_SYS_GRLIB_GAISLER_DDRSPA2_CTRL,
},
}
};
#endif
#endif
struct grlib_mctrl_handler grlib_mctrl_handlers[] = {
/* ESA MCTRL (PROM/FLASH/IO/SRAM/SDRAM) */
#ifdef CONFIG_SYS_GRLIB_ESA_MCTRL1
{DEV_APB_SLV, 0, MH_UNUSED, AMBA_PNP_ID(VENDOR_ESA, ESA_MCTRL),
_nomem_mctrl_init, (void *)&esa_mctrl1_cfg},
#ifdef CONFIG_SYS_GRLIB_ESA_MCTRL2
{DEV_APB_SLV, 1, MH_UNUSED, AMBA_PNP_ID(VENDOR_ESA, ESA_MCTRL),
_nomem_mctrl_init, (void *)&esa_mctrl2_cfg},
#endif
#endif
/* GAISLER Fault Tolerant Memory controller (PROM/FLASH/IO/SRAM/SDRAM) */
#ifdef CONFIG_SYS_GRLIB_GAISLER_FTMCTRL1
{DEV_APB_SLV, 0, MH_UNUSED, AMBA_PNP_ID(VENDOR_GAISLER, GAISLER_FTMCTRL),
_nomem_mctrl_init, (void *)&gaisler_ftmctrl1_cfg},
#ifdef CONFIG_SYS_GRLIB_GAISLER_FTMCTRL2
{DEV_APB_SLV, 1, MH_UNUSED, AMBA_PNP_ID(VENDOR_GAISLER, GAISLER_FTMCTRL),
_nomem_mctrl_init, (void *)&gaisler_ftmctrl2_cfg},
#endif
#endif
/* GAISLER SDRAM-only Memory controller (SDRAM) */
#ifdef CONFIG_SYS_GRLIB_GAISLER_SDCTRL1
{DEV_APB_SLV, 0, MH_UNUSED, AMBA_PNP_ID(VENDOR_GAISLER, GAISLER_SDCTRL),
_nomem_mctrl_init, (void *)&gaisler_sdctrl1_cfg},
#ifdef CONFIG_SYS_GRLIB_GAISLER_SDCTRL2
{DEV_APB_SLV, 1, MH_UNUSED, AMBA_PNP_ID(VENDOR_GAISLER, GAISLER_SDCTRL),
_nomem_mctrl_init, (void *)&gaisler_sdctrl2_cfg},
#endif
#endif
/* GAISLER DDR Memory controller (DDR) */
#ifdef CONFIG_SYS_GRLIB_GAISLER_DDRSPA1
{DEV_AHB_SLV, 0, MH_UNUSED, AMBA_PNP_ID(VENDOR_GAISLER, GAISLER_DDRSP),
_nomem_ahbmctrl_init, (void *)&gaisler_ddrspa1_cfg},
#ifdef CONFIG_SYS_GRLIB_GAISLER_DDRSPA2
{DEV_AHB_SLV, 1, MH_UNUSED, AMBA_PNP_ID(VENDOR_GAISLER, GAISLER_DDRSP),
_nomem_ahbmctrl_init, (void *)&gaisler_ddrspa2_cfg},
#endif
#endif
/* GAISLER DDR2 Memory controller (DDR2) */
#ifdef CONFIG_SYS_GRLIB_GAISLER_DDR2SPA1
{DEV_AHB_SLV, 0, MH_UNUSED, AMBA_PNP_ID(VENDOR_GAISLER, GAISLER_DDR2SP),
_nomem_ahbmctrl_init, (void *)&gaisler_ddr2spa1_cfg},
#ifdef CONFIG_SYS_GRLIB_GAISLER_DDR2SPA2
{DEV_AHB_SLV, 1, MH_UNUSED, AMBA_PNP_ID(VENDOR_GAISLER, GAISLER_DDR2SP),
_nomem_ahbmctrl_init, (void *)&gaisler_ddr2spa2_cfg},
#endif
#endif
/* Mark end */
MH_END
};

View File

@@ -0,0 +1,90 @@
/* GRLIB Memory controller setup structures
*
* (C) Copyright 2010, 2015
* Daniel Hellstrom, Cobham Gaisler, daniel@gaisler.com.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#ifndef __MEMCFG_H__
#define __MEMCFG_H__
/*********** Low Level Memory Controller Initalization ***********/
#ifndef __ASSEMBLER__
struct grlib_mctrl_handler;
typedef void (*mctrl_handler_t)(
struct grlib_mctrl_handler *dev,
void *conf,
unsigned int ioarea
);
/* Memory Controller Handler Structure */
struct grlib_mctrl_handler {
unsigned char type; /* 0x00. MASK: AHB MST&SLV, APB SLV */
char index; /* 0x01. Unit number, 0, 1, 2... */
char unused[2]; /* 0x02 */
unsigned int ven_dev; /* 0x04. Device and Vendor */
mctrl_handler_t func; /* 0x08. Memory Controller Handler */
void *priv; /* 0x0c. Optional private data, ptr to
* info how to set up controller */
};
extern struct grlib_mctrl_handler grlib_mctrl_handlers[];
#endif
#define MH_STRUCT_SIZE (4*4)
#define MH_TYPE 0x00
#define MH_INDEX 0x01
#define MH_VENDOR_DEVICE 0x04
#define MH_FUNC 0x08
#define MH_PRIV 0x0c
#define MH_TYPE_NONE DEV_NONE
#define MH_TYPE_AHB_MST DEV_AHB_MST
#define MH_TYPE_AHB_SLV DEV_AHB_SLV
#define MH_TYPE_APB_SLV DEV_APB_SLV
#define MH_UNUSED {0, 0}
#define MH_END {DEV_NONE, 0, MH_UNUSED, AMBA_PNP_ID(0, 0), 0, 0}
/*********** Low Level Memory Controller Initalization Handlers ***********/
#ifndef __ASSEMBLER__
extern void _nomem_mctrl_init(
struct grlib_mctrl_handler *dev,
void *conf,
unsigned int ioarea_apbmst);
struct mctrl_setup {
unsigned int reg_mask; /* Which registers to write */
struct {
unsigned int mask; /* Mask used keep reg bits unchanged */
unsigned int value; /* Value written to register */
} regs[8];
};
extern void _nomem_ahbmctrl_init(
struct grlib_mctrl_handler *dev,
void *conf,
unsigned int ioarea_apbmst);
struct ahbmctrl_setup {
int ahb_mbar_no; /* MBAR to get register address from */
unsigned int reg_mask; /* Which registers to write */
struct {
unsigned int mask; /* Mask used keep reg bits unchanged */
unsigned int value; /* Value written to register */
} regs[8];
};
#endif
/* mctrl_setup data structure defines */
#define NREGS_OFS 0
#define REGS_OFS 0x4
#define REGS_SIZE 8
#endif

View File

@@ -0,0 +1,253 @@
/* This is the memory initialization functions, the function
* implemented below initializes each memory controller
* found and specified by the input grlib_mctrl_handler structure.
*
* After the memory controllers have been initialized the stack
* can be used.
*
* (C) Copyright 2010, 2015
* Daniel Hellstrom, Cobham Gaisler, daniel@gaisler.com.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <ambapp.h>
#include "memcfg.h"
#include <config.h>
.seg "text"
.globl _nomem_memory_ctrl_init
.globl _nomem_mctrl_init, _nomem_ahbmctrl_init
.extern _nomem_find_apb
.extern _nomem_find_ahb
/* FUNCTION
* _nomem_memory_controller_init(struct grlib_mctrl_handler *mem_handlers)
*
* Initialize AMBA devices, _nomem_amba_init() has prepared i0-i5
* with the AHB buses on the system.
*
* For each entry in mem_handlers find the VENDOR:DEVICE and handle it
* by calling the handler function pointer.
*
* Constraints:
* i6, i7, o6, l7, l6, g3, g4, g5, g6, g7 is used by caller
* o7 is return address
* l5 reserved for this function for future use.
*
* Arguments
* - o0 Pointer to memory handler array
*
* Results
* - o0 Number of memory controllers found
*
* Clobbered
* - o0 (Current AHB slave conf address)
* - l0 (mem handler entry address)
* - l1 (Return value, number of memory controllers found)
* - o7 (function pointer)
* - l0, l1, l2, l3, l4, g1, g2 (used by _nomem_ambapp_find_buses)
* - o0, o1, o2, o3, o4, o5 (Used as arguments)
*
* - g1 ( level 1 return address)
* - g2 ( level 2 return address)
*/
_nomem_memory_ctrl_init:
/* At this point all AHB buses has been found and the I/O Areas of
* all AHB buses is stored in the i0-i5 registers. Max 6 buses. Next,
* memory controllers are found by searching all buses for matching
* VENDOR:DEVICE. The VENDOR:DEVICE to search for are taken from the
* mem_handlers array. For each match the function pointer stored in
* the mem_handler entry is called to handle the hardware setup.
*/
mov %o7, %g1 /* Save return address */
mov %o0, %l0
mov %g0, %l1 /* The return value */
.L_do_one_mem_handler:
ld [%l0 + MH_FUNC], %o7
cmp %o7, %g0
be .L_all_mctrl_handled
nop
/*** Scan for memory controller ***/
/* Set up argments, o5 not used by _nomem_find_apb */
ldub [%l0 + MH_TYPE], %o5
clr %o4
clr %o3
ldub [%l0 + MH_INDEX], %o2
ld [%l0 + MH_VENDOR_DEVICE], %o1
/* An empty config? */
cmp %o5, DEV_NONE
beq .L_all_mctrl_next
/* Select function (APB or AHB) */
cmp %o5, DEV_APB_SLV
bne .L_find_ahb_memctrl
clr %o0
.L_find_apb_memctrl:
call _nomem_find_apb /* Scan for APB slave device */
nop
/* o3 = iobar address
* o4 = AHB Bus index
*
* REG ADR = ((iobar >> 12) & (iobar << 4) & 0xfff00) | "APB Base"
*/
ld [%o3 + AMBA_APB_IOBAR_OFS], %o5
srl %o5, 12, %o2
sll %o5, 4, %o5
and %o2, %o5, %o5
set 0xfff00, %o2
and %o2, %o5, %o5
sethi %hi(0xfff00000), %o2
and %o3, %o2, %o2
or %o5, %o2, %o5 /* Register base address */
ba .L_call_one_mem_handler
nop
.L_find_ahb_memctrl:
call _nomem_find_ahb /* Scan for AHB Slave or Master.
* o5 determine type. */
nop
clr %o5
/* Call the handler function if the hardware was found
*
* o0 = mem_handler
* o1 = Configuration address
* o2 = AHB Bus index
* o3 = APB Base register (if APB Slave)
*
* Constraints:
* i0-i7, l0, l1, l5, g1, g3-g7 may no be used.
*/
.L_call_one_mem_handler:
cmp %o0, %g0
be .L_all_mctrl_next
mov %l0, %o0 /* Mem handler pointer */
mov %o3, %o1 /* AMBA PnP Configuration address */
mov %o4, %o2 /* AHB Bus index */
ld [%l0 + MH_FUNC], %o7 /* Get Function pointer */
call %o7
mov %o5, %o3 /* APB Register Base Address */
inc %l1 /* Number of Memory controllers
* handled. */
/* Do next entry in mem_handlers */
.L_all_mctrl_next:
ba .L_do_one_mem_handler
add %l0, MH_STRUCT_SIZE, %l0
.L_all_mctrl_handled:
mov %g1, %o7 /* Restore return address */
retl
mov %l1, %o0
/* Generic Memory controller initialization routine (APB Registers)
*
* o0 = mem_handler structure pointer
* o1 = Configuration address
* o2 = AHB Bus index
* o3 = APB Base register
*
* Clobbered
* o0-o4
*/
_nomem_mctrl_init:
ld [%o0 + MH_PRIV], %o0 /* Get Private structure */
ld [%o0], %o1 /* Get Reg Mask */
and %o1, 0xff, %o1
add %o0, REGS_OFS, %o0 /* Point to first reg */
.L_do_one_reg:
andcc %o1, 0x1, %g0
beq .L_do_next_reg
ld [%o0], %o2
ld [%o3], %o4
and %o4, %o2, %o4
ld [%o0 + 4], %o2
or %o4, %o2, %o4
st %o4, [%o3]
.L_do_next_reg:
add %o0, REGS_SIZE, %o0
add %o3, 4, %o3
srl %o1, 1, %o1
cmp %o1, 0
bne .L_do_one_reg
nop
/* No more registers to write */
retl
nop
/* Generic Memory controller initialization routine (AHB Registers)
*
* o0 = mem_handler structure pointer
* o1 = Configuration address of memory controller
* o2 = AHB Bus index
*
* Clobbered
* o0-o5
*/
_nomem_ahbmctrl_init:
ld [%o0 + MH_PRIV], %o0 /* Get Private structure */
/* Get index of AHB MBAR to get registers from */
ld [%o0], %o5
add %o0, 4, %o0
/* Get Address of MBAR in PnP info */
add %o5, 4, %o5
sll %o5, 2, %o5
add %o5, %o1, %o5 /* Address of MBAR */
/* Get Address of registers from PnP information
* Address is in AHB I/O format, i.e. relative to bus
*
* ADR = (iobar & (iobar << 16) & 0xfff00000)
* IOADR = (ADR >> 12) | "APB Base"
*/
ld [%o5], %o5
sll %o5, 16, %o4
and %o5, %o4, %o5
sethi %hi(0xfff00000), %o4
and %o5, %o4, %o5 /* ADR */
and %o4, %o1, %o4
srl %o5, 12, %o5
or %o5, %o4, %o3 /* IOADR in o3 */
ld [%o0], %o1 /* Get Reg Mask */
and %o1, 0xff, %o1
add %o0, REGS_OFS, %o0 /* Point to first reg */
.L_do_one_ahbreg:
andcc %o1, 0x1, %g0
beq .L_do_next_reg
ld [%o0], %o2
ld [%o3], %o4
and %o4, %o2, %o4
ld [%o0 + 4], %o2
or %o4, %o2, %o4
st %o4, [%o3]
.L_do_next_ahbreg:
add %o0, REGS_SIZE, %o0
add %o3, 4, %o3
srl %o1, 1, %o1
cmp %o1, 0
bne .L_do_one_reg
nop
/* No more registers to write */
retl
nop

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,189 @@
/* GRLIB APBUART Serial controller driver
*
* (C) Copyright 2007, 2015
* Daniel Hellstrom, Cobham Gaisler, daniel@gaisler.com.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <asm/io.h>
#include <ambapp.h>
#include <grlib/apbuart.h>
#include <serial.h>
#include <watchdog.h>
DECLARE_GLOBAL_DATA_PTR;
/* Select which UART that will become u-boot console */
#ifndef CONFIG_SYS_GRLIB_APBUART_INDEX
/* Try to use CONFIG_CONS_INDEX, if available, it is numbered from 1 */
#ifdef CONFIG_CONS_INDEX
#define CONFIG_SYS_GRLIB_APBUART_INDEX (CONFIG_CONS_INDEX - 1)
#else
#define CONFIG_SYS_GRLIB_APBUART_INDEX 0
#endif
#endif
static unsigned apbuart_calc_scaler(unsigned apbuart_freq, unsigned baud)
{
return (((apbuart_freq * 10) / (baud * 8)) - 5) / 10;
}
static int leon3_serial_init(void)
{
ambapp_dev_apbuart *uart;
ambapp_apbdev apbdev;
unsigned int tmp;
/* find UART */
if (ambapp_apb_find(&ambapp_plb, VENDOR_GAISLER, GAISLER_APBUART,
CONFIG_SYS_GRLIB_APBUART_INDEX, &apbdev) != 1) {
gd->flags &= ~GD_FLG_SERIAL_READY;
panic("%s: apbuart not found!\n", __func__);
return -1; /* didn't find hardware */
}
/* found apbuart, let's init .. */
uart = (ambapp_dev_apbuart *) apbdev.address;
/* APBUART Frequency is equal to bus frequency */
gd->arch.uart_freq = ambapp_bus_freq(&ambapp_plb, apbdev.ahb_bus_index);
/* Set scaler / baud rate */
tmp = apbuart_calc_scaler(gd->arch.uart_freq, CONFIG_BAUDRATE);
writel(tmp, &uart->scaler);
/* Let bit 11 be unchanged (debug bit for GRMON) */
tmp = readl(&uart->ctrl) & APBUART_CTRL_DBG;
/* Receiver & transmitter enable */
tmp |= APBUART_CTRL_RE | APBUART_CTRL_TE;
writel(tmp, &uart->ctrl);
gd->arch.uart = uart;
return 0;
}
static inline ambapp_dev_apbuart *leon3_get_uart_regs(void)
{
ambapp_dev_apbuart *uart = gd->arch.uart;
return uart;
}
static void leon3_serial_putc_raw(const char c)
{
ambapp_dev_apbuart * const uart = leon3_get_uart_regs();
if (!uart)
return;
/* Wait for last character to go. */
while (!(readl(&uart->status) & APBUART_STATUS_THE))
WATCHDOG_RESET();
/* Send data */
writel(c, &uart->data);
#ifdef LEON_DEBUG
/* Wait for data to be sent */
while (!(readl(&uart->status) & APBUART_STATUS_TSE))
WATCHDOG_RESET();
#endif
}
static void leon3_serial_putc(const char c)
{
if (c == '\n')
leon3_serial_putc_raw('\r');
leon3_serial_putc_raw(c);
}
static int leon3_serial_getc(void)
{
ambapp_dev_apbuart * const uart = leon3_get_uart_regs();
if (!uart)
return 0;
/* Wait for a character to arrive. */
while (!(readl(&uart->status) & APBUART_STATUS_DR))
WATCHDOG_RESET();
/* Read character data */
return readl(&uart->data);
}
static int leon3_serial_tstc(void)
{
ambapp_dev_apbuart * const uart = leon3_get_uart_regs();
if (!uart)
return 0;
return readl(&uart->status) & APBUART_STATUS_DR;
}
/* set baud rate for uart */
static void leon3_serial_setbrg(void)
{
ambapp_dev_apbuart * const uart = leon3_get_uart_regs();
unsigned int scaler;
if (!uart)
return;
if (!gd->baudrate)
gd->baudrate = CONFIG_BAUDRATE;
if (!gd->arch.uart_freq)
gd->arch.uart_freq = CONFIG_SYS_CLK_FREQ;
scaler = apbuart_calc_scaler(gd->arch.uart_freq, gd->baudrate);
writel(scaler, &uart->scaler);
}
static struct serial_device leon3_serial_drv = {
.name = "leon3_serial",
.start = leon3_serial_init,
.stop = NULL,
.setbrg = leon3_serial_setbrg,
.putc = leon3_serial_putc,
.puts = default_serial_puts,
.getc = leon3_serial_getc,
.tstc = leon3_serial_tstc,
};
void leon3_serial_initialize(void)
{
serial_register(&leon3_serial_drv);
}
__weak struct serial_device *default_serial_console(void)
{
return &leon3_serial_drv;
}
#ifdef CONFIG_DEBUG_UART_APBUART
#include <debug_uart.h>
static inline void _debug_uart_init(void)
{
ambapp_dev_apbuart *uart = (ambapp_dev_apbuart *)CONFIG_DEBUG_UART_BASE;
uart->scaler = apbuart_calc_scaler(CONFIG_DEBUG_UART_CLOCK, CONFIG_BAUDRATE);
uart->ctrl = APBUART_CTRL_RE | APBUART_CTRL_TE;
}
static inline void _debug_uart_putc(int ch)
{
ambapp_dev_apbuart *uart = (ambapp_dev_apbuart *)CONFIG_DEBUG_UART_BASE;
while (!(readl(&uart->status) & APBUART_STATUS_THE))
WATCHDOG_RESET();
writel(ch, &uart->data);
}
DEBUG_UART_FUNCS
#endif

View File

@@ -0,0 +1,681 @@
/* This is where the SPARC/LEON3 starts
*
* Copyright (C) 2007, 2015
* Daniel Hellstrom, Cobham Gaisler, daniel@gaisler.com
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <asm-offsets.h>
#include <config.h>
#include <asm/asmmacro.h>
#include <asm/winmacro.h>
#include <asm/psr.h>
#include <asm/stack.h>
#include <asm/leon.h>
#include <ambapp.h>
/* Default Plug&Play I/O area */
#ifndef CONFIG_AMBAPP_IOAREA
#define CONFIG_AMBAPP_IOAREA AMBA_DEFAULT_IOAREA
#endif
/* Default number of SPARC register windows */
#ifndef CONFIG_SYS_SPARC_NWINDOWS
#define CONFIG_SYS_SPARC_NWINDOWS 8
#endif
/* Entry for traps which jump to a programmer-specified trap handler. */
#define TRAPR(H) \
wr %g0, 0xfe0, %psr; \
mov %g0, %tbr; \
ba (H); \
mov %g0, %wim;
#define TRAP(H) \
mov %psr, %l0; \
ba (H); \
nop; nop;
#define TRAPI(ilevel) \
mov ilevel, %l7; \
mov %psr, %l0; \
b _irq_entry; \
mov %wim, %l3
/* Unexcpected trap will halt the processor by forcing it to error state */
#undef BAD_TRAP
#define BAD_TRAP ta 0; nop; nop; nop;
/* Software trap. Treat as BAD_TRAP for the time being... */
#define SOFT_TRAP TRAP(_hwerr)
#define PSR_INIT 0x1FC0 /* Disable traps, set s and ps */
#define WIM_INIT 2
/* All traps low-level code here must end with this macro. */
#define RESTORE_ALL b ret_trap_entry; clr %l6;
#define WRITE_PAUSE nop;nop;nop
WINDOWSIZE = (16 * 4)
ARGPUSHSIZE = (6 * 4)
ARGPUSH = (WINDOWSIZE + 4)
MINFRAME = (WINDOWSIZE + ARGPUSHSIZE + 4)
/* Number of register windows */
#ifndef CONFIG_SYS_SPARC_NWINDOWS
#error Must define number of SPARC register windows, default is 8
#endif
/* Macros to load address into a register. Uses GOT table for PIC */
#ifdef __PIC__
#define SPARC_PIC_THUNK_CALL(reg) \
sethi %pc22(_GLOBAL_OFFSET_TABLE_-4), %##reg; \
call __sparc_get_pc_thunk.reg; \
add %##reg, %pc10(_GLOBAL_OFFSET_TABLE_+4), %##reg;
#define SPARC_LOAD_ADDRESS(sym, got, reg) \
sethi %gdop_hix22(sym), %##reg; \
xor %##reg, %gdop_lox10(sym), %##reg; \
ld [%##got + %##reg], %##reg, %gdop(sym);
#else
#define SPARC_PIC_THUNK_CALL(reg)
#define SPARC_LOAD_ADDRESS(sym, got, tmp) \
set sym, %##reg;
#endif
#define STACK_ALIGN 8
#define SA(X) (((X)+(STACK_ALIGN-1)) & ~(STACK_ALIGN-1))
.section ".start", "ax"
.globl _start, start, _trap_table
.globl _irq_entry, nmi_trap
.globl _reset_reloc
/* at address 0
* Hardware traps
*/
start:
_start:
_trap_table:
TRAPR(_hardreset); ! 00 reset trap
BAD_TRAP; ! 01 instruction_access_exception
BAD_TRAP; ! 02 illegal_instruction
BAD_TRAP; ! 03 priveleged_instruction
BAD_TRAP; ! 04 fp_disabled
TRAP(_window_overflow); ! 05 window_overflow
TRAP(_window_underflow); ! 06 window_underflow
BAD_TRAP; ! 07 Memory Address Not Aligned
BAD_TRAP; ! 08 Floating Point Exception
BAD_TRAP; ! 09 Data Miss Exception
BAD_TRAP; ! 0a Tagged Instruction Ovrflw
BAD_TRAP; ! 0b Watchpoint Detected
BAD_TRAP; ! 0c
BAD_TRAP; ! 0d
BAD_TRAP; ! 0e
BAD_TRAP; ! 0f
BAD_TRAP; ! 10
TRAPI(1); ! 11 IRQ level 1
TRAPI(2); ! 12 IRQ level 2
TRAPI(3); ! 13 IRQ level 3
TRAPI(4); ! 14 IRQ level 4
TRAPI(5); ! 15 IRQ level 5
TRAPI(6); ! 16 IRQ level 6
TRAPI(7); ! 17 IRQ level 7
TRAPI(8); ! 18 IRQ level 8
TRAPI(9); ! 19 IRQ level 9
TRAPI(10); ! 1a IRQ level 10
TRAPI(11); ! 1b IRQ level 11
TRAPI(12); ! 1c IRQ level 12
TRAPI(13); ! 1d IRQ level 13
TRAPI(14); ! 1e IRQ level 14
TRAP(_nmi_trap); ! 1f IRQ level 15 /
! NMI (non maskable interrupt)
BAD_TRAP; ! 20 r_register_access_error
BAD_TRAP; ! 21 instruction access error
BAD_TRAP; ! 22
BAD_TRAP; ! 23
BAD_TRAP; ! 24 co-processor disabled
BAD_TRAP; ! 25 uniplemented FLUSH
BAD_TRAP; ! 26
BAD_TRAP; ! 27
BAD_TRAP; ! 28 co-processor exception
BAD_TRAP; ! 29 data access error
BAD_TRAP; ! 2a division by zero
BAD_TRAP; ! 2b data store error
BAD_TRAP; ! 2c data access MMU miss
BAD_TRAP; ! 2d
BAD_TRAP; ! 2e
BAD_TRAP; ! 2f
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 30-33
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 34-37
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 38-3b
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 3c-3f
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 40-43
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 44-47
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 48-4b
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 4c-4f
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 50-53
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 54-57
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 58-5b
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 5c-5f
/* implementaion dependent */
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 60-63
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 64-67
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 68-6b
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 6c-6f
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 70-73
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 74-77
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 78-7b
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 7c-7f
/* Software traps, not handled */
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 80-83
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 84-87
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 88-8b
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 8c-8f
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 90-93
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 94-97
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 98-9b
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 9c-9f
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! a0-a3
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! a4-a7
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! a8-ab
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! ac-af
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! b0-b3
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! b4-b7
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! b8-bb
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! bc-bf
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! c0-c3
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! c4-c7
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! c8-cb
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! cc-cf
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! d0-d3
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! d4-d7
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! d8-db
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! dc-df
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! e0-e3
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! e4-e7
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! e8-eb
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! ec-ef
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! f0-f3
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! f4-f7
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! f8-fb
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! fc-ff
.section ".text"
.extern _nomem_amba_init, _nomem_memory_ctrl_init
.align 4
_hardreset:
1000:
flush
/* Enable I/D-Cache and Snooping */
set 0x0081000f, %g2
sta %g2, [%g0] 2
mov %g0, %y
clr %g1
clr %g2
clr %g3
clr %g4
clr %g5
clr %g6
clr %g7
mov %asr17, %g3
and %g3, 0x1f, %g3
clear_window:
mov %g0, %l0
mov %g0, %l1
mov %g0, %l2
mov %g0, %l3
mov %g0, %l4
mov %g0, %l5
mov %g0, %l6
mov %g0, %l7
mov %g0, %o0
mov %g0, %o1
mov %g0, %o2
mov %g0, %o3
mov %g0, %o4
mov %g0, %o5
mov %g0, %o6
mov %g0, %o7
subcc %g3, 1, %g3
bge clear_window
save
wiminit:
set WIM_INIT, %g3
mov %g3, %wim
stackinit:
set CONFIG_SYS_INIT_SP_OFFSET, %fp
andn %fp, 0x0f, %fp
sub %fp, 64, %sp
tbrinit:
set CONFIG_SYS_TEXT_BASE, %g2
wr %g0, %g2, %tbr
nop
nop
nop
/* Obtain the address of _GLOBAL_OFFSET_TABLE_ */
SPARC_PIC_THUNK_CALL(l7)
/* Scan AMBA Bus for AMBA buses using PnP information. All found
* AMBA buses I/O area will be located in i0-i5 upon return.
* The i0-i5 registers are later used by _nomem_amba_init2
*/
ambainit:
call _nomem_amba_init
sethi %hi(CONFIG_AMBAPP_IOAREA), %o0
/* Scan AMBA Buses for memory controllers, then initialize the
* memory controllers. Note that before setting up the memory controller
* the stack can not be used.
*/
memory_ctrl_init:
SPARC_LOAD_ADDRESS(grlib_mctrl_handlers, l7, o0)
call _nomem_memory_ctrl_init
nop
/* The return valu indicate how many memory controllers where found and
* initialized, if no memory controller was initialized, we can not continue
* because from here on we expect memory to be working.
*/
cmp %o0, 0
memory_ctrl_init_failed:
beq memory_ctrl_init_failed
nop
/*** From now on the stack can be used. ***/
cpu_init_unreloc:
call cpu_init_f
nop
board_init_unreloc:
call board_init_f
clr %o0 ! boot_flags
dead_unreloc:
mov 1, %g1 ! For GRMON2 to exit normally.
ta 0 ! If board_init_f call returns.. (unlikely)
nop
nop
ba dead_unreloc ! infinte loop
nop
!-------------------------------------------------------------------------------
/* void relocate_code (addr_sp, gd, addr_moni)
*
* This "function" does not return, instead it continues in RAM after
* relocating the monitor code.
*
* %o0 = Relocated stack pointer
* %o1 = Relocated global data pointer
* %o2 = Relocated text pointer
*
* %l7 = _GLOBAL_OFFSET_TABLE_ address
*/
.globl relocate_code
.type relocate_code, #function
.align 4
relocate_code:
!SPARC_PIC_THUNK_CALL(l7)
reloc:
SPARC_LOAD_ADDRESS(_text, l7, g2) ! start address of monitor
SPARC_LOAD_ADDRESS(__init_end, l7, g3) ! end address of monitor
mov %o2, %g4 ! relocation address
sub %g4, %g2, %g6 ! relocation offset
/* copy .text & .data to relocated address */
10: ldd [%g2], %l0
ldd [%g2+8], %l2
std %l0, [%g4]
std %l2, [%g4+8]
inc 16, %g2 ! src += 16
cmp %g2, %g3
bcs 10b ! while (src < end)
inc 16, %g4 ! dst += 16
clr %l0
clr %l1
clr %l2
clr %l3
clr %g2
/* register g4 contain address to start
* This means that BSS must be directly after data and code segments
*
* g3 is length of bss = (__bss_end-__bss_start)
*
*/
/* clear the relocated .bss area */
clr_bss:
SPARC_LOAD_ADDRESS(__bss_start, l7, g2)
SPARC_LOAD_ADDRESS(__bss_end, l7, g3)
sub %g3,%g2,%g3 ! length of .bss area
add %g3,%g4,%g3
/* clearing 16byte a time ==> linker script need to align to 16 byte offset */
clr %g1 /* std %g0 uses g0 and g1 */
20:
std %g0, [%g4]
std %g0, [%g4+8]
inc 16, %g4 ! ptr += 16
cmp %g4, %g3
bcs 20b ! while (ptr < end)
nop
/* add offsets to GOT table */
fixup_got:
SPARC_LOAD_ADDRESS(__got_start, l7, g4)
add %g4, %g6, %g4
SPARC_LOAD_ADDRESS(__got_end, l7, g3)
add %g3, %g6, %g3
30: ld [%g4], %l0
#ifdef CONFIG_RELOC_GOT_SKIP_NULL
cmp %l0, 0
be 32f
#endif
add %l0, %g6, %l0 ! relocate GOT pointer
st %l0, [%g4]
32: inc 4, %g4 ! ptr += 4
cmp %g4, %g3
bcs 30b ! while (ptr < end)
nop
prom_relocate:
SPARC_LOAD_ADDRESS(__prom_start, l7, g2)
SPARC_LOAD_ADDRESS(__prom_end, l7, g3)
/*
* Calculated addres is stored in this variable by
* reserve_prom() function in common/board_f.c
*/
SPARC_LOAD_ADDRESS(__prom_start_reloc, l7, g4)
ld [%g4], %g4
40: ldd [%g2], %l0
ldd [%g2+8], %l2
std %l0, [%g4]
std %l2, [%g4+8]
inc 16, %g2
cmp %g2, %g3
bcs 40b
inc 16, %g4
! %o0 = stack pointer (relocated)
! %o1 = global data pointer (relocated)
! %o2 = text pointer (relocated)
! %g6 = relocation offset
! %l7 = _GLOBAL_OFFSET_TABLE_
/* Trap table has been moved, lets tell CPU about
* the new trap table address
*/
update_trap_table_address:
wr %g0, %o2, %tbr
nop
nop
nop
update_stack_pointers:
mov %o0, %fp
andn %fp, 0x0f, %fp ! align to 16 bytes
add %fp, -64, %fp ! make space for a window push
mov %fp, %sp ! setup stack pointer
jump_board_init_r:
mov %o1, %o0 ! relocated global data pointer
mov %o2, %o1 ! relocated text pointer
SPARC_LOAD_ADDRESS(board_init_r, l7, o3)
add %o3, %g6, %o3 ! add relocation offset
call %o3
nop
dead:
mov 1, %g1 ! For GRMON2 to exit normally.
ta 0 ! if call returns.. (unlikely)
nop
b dead ! infinte loop
nop
!------------------------------------------------------------------------------
/* Interrupt handler caller,
* reg L7: interrupt number
* reg L0: psr after interrupt
* reg L1: PC
* reg L2: next PC
* reg L3: wim
*/
_irq_entry:
SAVE_ALL
or %l0, PSR_PIL, %g2
wr %g2, 0x0, %psr
WRITE_PAUSE
wr %g2, PSR_ET, %psr
WRITE_PAUSE
mov %l7, %o0 ! irq level
set handler_irq, %o1
set (CONFIG_SYS_RELOC_MONITOR_BASE-CONFIG_SYS_TEXT_BASE), %o2
add %o1, %o2, %o1
call %o1
add %sp, SF_REGS_SZ, %o1 ! pt_regs ptr
or %l0, PSR_PIL, %g2 ! restore PIL after handler_irq
wr %g2, PSR_ET, %psr ! keep ET up
WRITE_PAUSE
RESTORE_ALL
!------------------------------------------------------------------------------
/*
* Window overflow trap handler
*/
.global _window_overflow
_window_overflow:
mov %wim, %l3 ! Calculate next WIM
mov %g1, %l7
srl %l3, 1, %g1
sll %l3, (CONFIG_SYS_SPARC_NWINDOWS-1), %l4
or %g1, %l4, %g1
save ! Get into window to be saved.
mov %g1, %wim
nop; nop; nop
st %l0, [%sp + 0] ! Save window to the stack
st %l1, [%sp + 4]
st %l2, [%sp + 8]
st %l3, [%sp + 12]
st %l4, [%sp + 16]
st %l5, [%sp + 20]
st %l6, [%sp + 24]
st %l7, [%sp + 28]
st %i0, [%sp + 32]
st %i1, [%sp + 36]
st %i2, [%sp + 40]
st %i3, [%sp + 44]
st %i4, [%sp + 48]
st %i5, [%sp + 52]
st %i6, [%sp + 56]
st %i7, [%sp + 60]
restore ! Go back to trap window.
mov %l7, %g1
jmp %l1 ! Re-execute save.
rett %l2
/*
* Window underflow trap handler
*/
.global _window_underflow
_window_underflow:
mov %wim, %l3 ! Calculate next WIM
srl %l3, (CONFIG_SYS_SPARC_NWINDOWS-1), %l5
sll %l3, 1, %l4
or %l5, %l4, %l5
mov %l5, %wim
nop; nop; nop
restore ! Two restores to get into the
restore ! window to restore
ld [%sp + 0], %l0; ! Restore window from the stack
ld [%sp + 4], %l1;
ld [%sp + 8], %l2;
ld [%sp + 12], %l3;
ld [%sp + 16], %l4;
ld [%sp + 20], %l5;
ld [%sp + 24], %l6;
ld [%sp + 28], %l7;
ld [%sp + 32], %i0;
ld [%sp + 36], %i1;
ld [%sp + 40], %i2;
ld [%sp + 44], %i3;
ld [%sp + 48], %i4;
ld [%sp + 52], %i5;
ld [%sp + 56], %i6;
ld [%sp + 60], %i7;
save ! Get back to the trap window.
save
jmp %l1 ! Re-execute restore.
rett %l2
!------------------------------------------------------------------------------
_nmi_trap:
nop
jmp %l1
rett %l2
_hwerr:
ta 0
nop
nop
b _hwerr ! loop infinite
nop
/* Registers to not touch at all. */
#define t_psr l0 /* Set by caller */
#define t_pc l1 /* Set by caller */
#define t_npc l2 /* Set by caller */
#define t_wim l3 /* Set by caller */
#define t_twinmask l4 /* Set at beginning of this entry routine. */
#define t_kstack l5 /* Set right before pt_regs frame is built */
#define t_retpc l6 /* If you change this, change winmacro.h header file */
#define t_systable l7 /* Never touch this, could be the syscall table ptr. */
#define curptr g6 /* Set after pt_regs frame is built */
trap_setup:
/* build a pt_regs trap frame. */
sub %fp, (SF_REGS_SZ + PT_REGS_SZ), %t_kstack
PT_STORE_ALL(t_kstack, t_psr, t_pc, t_npc, g2)
/* See if we are in the trap window. */
mov 1, %t_twinmask
sll %t_twinmask, %t_psr, %t_twinmask ! t_twinmask = (1 << psr)
andcc %t_twinmask, %t_wim, %g0
beq 1f ! in trap window, clean up
nop
/*-------------------------------------------------
* Spill , adjust %wim and go.
*/
srl %t_wim, 0x1, %g2 ! begin computation of new %wim
set (CONFIG_SYS_SPARC_NWINDOWS-1), %g3 !NWINDOWS-1
sll %t_wim, %g3, %t_wim ! NWINDOWS-1
or %t_wim, %g2, %g2
and %g2, 0xff, %g2
save %g0, %g0, %g0 ! get in window to be saved
/* Set new %wim value */
wr %g2, 0x0, %wim
/* Save the kernel window onto the corresponding stack. */
RW_STORE(sp)
restore %g0, %g0, %g0
/*-------------------------------------------------*/
1:
/* Trap from kernel with a window available.
* Just do it...
*/
jmpl %t_retpc + 0x8, %g0 ! return to caller
mov %t_kstack, %sp ! jump onto new stack
#define twin_tmp1 l4
#define glob_tmp g4
#define curptr g6
ret_trap_entry:
wr %t_psr, 0x0, %psr ! enable nesting again, clear ET
/* Will the rett land us in the invalid window? */
mov 2, %g1
sll %g1, %t_psr, %g1
set CONFIG_SYS_SPARC_NWINDOWS, %g2 !NWINDOWS
srl %g1, %g2, %g2
or %g1, %g2, %g1
rd %wim, %g2
andcc %g2, %g1, %g0
be 1f ! Nope, just return from the trap
sll %g2, 0x1, %g1
/* We have to grab a window before returning. */
set (CONFIG_SYS_SPARC_NWINDOWS-1), %g3 !NWINDOWS-1
srl %g2, %g3, %g2
or %g1, %g2, %g1
and %g1, 0xff, %g1
wr %g1, 0x0, %wim
/* Grrr, make sure we load from the right %sp... */
PT_LOAD_ALL(sp, t_psr, t_pc, t_npc, g1)
restore %g0, %g0, %g0
RW_LOAD(sp)
b 2f
save %g0, %g0, %g0
/* Reload the entire frame in case this is from a
* kernel system call or whatever...
*/
1:
PT_LOAD_ALL(sp, t_psr, t_pc, t_npc, g1)
2:
wr %t_psr, 0x0, %psr
nop;
nop;
nop
jmp %t_pc
rett %t_npc
/* This is called from relocated C-code.
* It resets the system by jumping to _start
*/
_reset_reloc:
set start, %l0
call %l0
nop

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,167 @@
/*
* (C) Copyright 2001
* Denis Peter, MPL AG Switzerland
*
* SPDX-License-Identifier: GPL-2.0+
*
* Note: Part of this code has been derived from linux
*/
#ifndef _USB_UHCI_H_
#define _USB_UHCI_H_
/* Command register */
#define USBCMD 0
#define USBCMD_RS 0x0001 /* Run/Stop */
#define USBCMD_HCRESET 0x0002 /* Host reset */
#define USBCMD_GRESET 0x0004 /* Global reset */
#define USBCMD_EGSM 0x0008 /* Global Suspend Mode */
#define USBCMD_FGR 0x0010 /* Force Global Resume */
#define USBCMD_SWDBG 0x0020 /* SW Debug mode */
#define USBCMD_CF 0x0040 /* Config Flag (sw only) */
#define USBCMD_MAXP 0x0080 /* Max Packet (0 = 32, 1 = 64) */
/* Status register */
#define USBSTS 2
#define USBSTS_USBINT 0x0001 /* Interrupt due to IOC */
#define USBSTS_ERROR 0x0002 /* Interrupt due to error */
#define USBSTS_RD 0x0004 /* Resume Detect */
#define USBSTS_HSE 0x0008 /* Host System Error - basically PCI problems */
#define USBSTS_HCPE 0x0010 /* Host Controller Process Error - the scripts were buggy */
#define USBSTS_HCH 0x0020 /* HC Halted */
/* Interrupt enable register */
#define USBINTR 4
#define USBINTR_TIMEOUT 0x0001 /* Timeout/CRC error enable */
#define USBINTR_RESUME 0x0002 /* Resume interrupt enable */
#define USBINTR_IOC 0x0004 /* Interrupt On Complete enable */
#define USBINTR_SP 0x0008 /* Short packet interrupt enable */
#define USBFRNUM 6
#define USBFLBASEADD 8
#define USBSOF 12
/* USB port status and control registers */
#define USBPORTSC1 16
#define USBPORTSC2 18
#define USBPORTSC_CCS 0x0001 /* Current Connect Status ("device present") */
#define USBPORTSC_CSC 0x0002 /* Connect Status Change */
#define USBPORTSC_PE 0x0004 /* Port Enable */
#define USBPORTSC_PEC 0x0008 /* Port Enable Change */
#define USBPORTSC_LS 0x0030 /* Line Status */
#define USBPORTSC_RD 0x0040 /* Resume Detect */
#define USBPORTSC_LSDA 0x0100 /* Low Speed Device Attached */
#define USBPORTSC_PR 0x0200 /* Port Reset */
#define USBPORTSC_SUSP 0x1000 /* Suspend */
/* Legacy support register */
#define USBLEGSUP 0xc0
#define USBLEGSUP_DEFAULT 0x2000 /* only PIRQ enable set */
#define UHCI_NULL_DATA_SIZE 0x7ff /* for UHCI controller TD */
#define UHCI_PID 0xff /* PID MASK */
#define UHCI_PTR_BITS 0x000F
#define UHCI_PTR_TERM 0x0001
#define UHCI_PTR_QH 0x0002
#define UHCI_PTR_DEPTH 0x0004
/* for TD <status>: */
#define TD_CTRL_SPD (1 << 29) /* Short Packet Detect */
#define TD_CTRL_C_ERR_MASK (3 << 27) /* Error Counter bits */
#define TD_CTRL_LS (1 << 26) /* Low Speed Device */
#define TD_CTRL_IOS (1 << 25) /* Isochronous Select */
#define TD_CTRL_IOC (1 << 24) /* Interrupt on Complete */
#define TD_CTRL_ACTIVE (1 << 23) /* TD Active */
#define TD_CTRL_STALLED (1 << 22) /* TD Stalled */
#define TD_CTRL_DBUFERR (1 << 21) /* Data Buffer Error */
#define TD_CTRL_BABBLE (1 << 20) /* Babble Detected */
#define TD_CTRL_NAK (1 << 19) /* NAK Received */
#define TD_CTRL_CRCTIMEO (1 << 18) /* CRC/Time Out Error */
#define TD_CTRL_BITSTUFF (1 << 17) /* Bit Stuff Error */
#define TD_CTRL_ACTLEN_MASK 0x7ff /* actual length, encoded as n - 1 */
#define TD_CTRL_ANY_ERROR (TD_CTRL_STALLED | TD_CTRL_DBUFERR | \
TD_CTRL_BABBLE | TD_CTRL_CRCTIME | TD_CTRL_BITSTUFF)
#define TD_TOKEN_TOGGLE 19
/* ------------------------------------------------------------------------------------
Virtual Root HUB
------------------------------------------------------------------------------------ */
/* destination of request */
#define RH_INTERFACE 0x01
#define RH_ENDPOINT 0x02
#define RH_OTHER 0x03
#define RH_CLASS 0x20
#define RH_VENDOR 0x40
/* Requests: bRequest << 8 | bmRequestType */
#define RH_GET_STATUS 0x0080
#define RH_CLEAR_FEATURE 0x0100
#define RH_SET_FEATURE 0x0300
#define RH_SET_ADDRESS 0x0500
#define RH_GET_DESCRIPTOR 0x0680
#define RH_SET_DESCRIPTOR 0x0700
#define RH_GET_CONFIGURATION 0x0880
#define RH_SET_CONFIGURATION 0x0900
#define RH_GET_STATE 0x0280
#define RH_GET_INTERFACE 0x0A80
#define RH_SET_INTERFACE 0x0B00
#define RH_SYNC_FRAME 0x0C80
/* Our Vendor Specific Request */
#define RH_SET_EP 0x2000
/* Hub port features */
#define RH_PORT_CONNECTION 0x00
#define RH_PORT_ENABLE 0x01
#define RH_PORT_SUSPEND 0x02
#define RH_PORT_OVER_CURRENT 0x03
#define RH_PORT_RESET 0x04
#define RH_PORT_POWER 0x08
#define RH_PORT_LOW_SPEED 0x09
#define RH_C_PORT_CONNECTION 0x10
#define RH_C_PORT_ENABLE 0x11
#define RH_C_PORT_SUSPEND 0x12
#define RH_C_PORT_OVER_CURRENT 0x13
#define RH_C_PORT_RESET 0x14
/* Hub features */
#define RH_C_HUB_LOCAL_POWER 0x00
#define RH_C_HUB_OVER_CURRENT 0x01
#define RH_DEVICE_REMOTE_WAKEUP 0x00
#define RH_ENDPOINT_STALL 0x01
/* Our Vendor Specific feature */
#define RH_REMOVE_EP 0x00
#define RH_ACK 0x01
#define RH_REQ_ERR -1
#define RH_NACK 0x00
/* Transfer descriptor structure */
typedef struct {
unsigned long link; /* next td/qh (LE) */
unsigned long status; /* status of the td */
unsigned long info; /* Max Lenght / Endpoint / device address and PID */
unsigned long buffer; /* pointer to data buffer (LE) */
unsigned long dev_ptr; /* pointer to the assigned device (BE) */
unsigned long res[3]; /* reserved (TDs must be 8Byte aligned) */
} uhci_td_t, *puhci_td_t;
/* Queue Header structure */
typedef struct {
unsigned long head; /* Next QH (LE) */
unsigned long element; /* Queue element pointer (LE) */
unsigned long res[5]; /* reserved */
unsigned long dev_ptr; /* if 0 no tds have been assigned to this qh */
} uhci_qh_t, *puhci_qh_t;
struct virt_root_hub {
int devnum; /* Address of Root Hub endpoint */
int numports; /* number of ports */
int c_p_r[8]; /* C_PORT_RESET */
};
#endif /* _USB_UHCI_H_ */