mirror of
https://gitlab.rtems.org/rtems/rtos/rtems.git
synced 2025-12-28 07:20:16 +00:00
bsps/mpc55xx: Move libcpu content to bsps
This patch is a part of the BSP source reorganization. Update #3285.
This commit is contained in:
@@ -108,13 +108,13 @@ endif
|
||||
|
||||
libbsp_a_SOURCES += ../../../../../../bsps/powerpc/shared/cache/cache.c
|
||||
libbsp_a_SOURCES += ../../../../../../bsps/powerpc/shared/ppc-dec-timer.c
|
||||
|
||||
libbsp_a_LIBADD = ../../../libcpu/@RTEMS_CPU@/@RTEMS_CPU_MODEL@/misc.rel \
|
||||
../../../libcpu/@RTEMS_CPU@/@RTEMS_CPU_MODEL@/irq.rel \
|
||||
../../../libcpu/@RTEMS_CPU@/@RTEMS_CPU_MODEL@/siu.rel \
|
||||
../../../libcpu/@RTEMS_CPU@/@RTEMS_CPU_MODEL@/edma.rel \
|
||||
../../../libcpu/@RTEMS_CPU@/@RTEMS_CPU_MODEL@/emios.rel \
|
||||
../../../libcpu/@RTEMS_CPU@/@RTEMS_CPU_MODEL@/dspi.rel
|
||||
libbsp_a_SOURCES += ../../../../../../bsps/powerpc/mpc55xxevb/dev/dspi.c
|
||||
libbsp_a_SOURCES += ../../../../../../bsps/powerpc/mpc55xxevb/start/copy.S
|
||||
libbsp_a_SOURCES += ../../../../../../bsps/powerpc/mpc55xxevb/start/edma.c
|
||||
libbsp_a_SOURCES += ../../../../../../bsps/powerpc/mpc55xxevb/start/emios.c
|
||||
libbsp_a_SOURCES += ../../../../../../bsps/powerpc/mpc55xxevb/start/flash_support.c
|
||||
libbsp_a_SOURCES += ../../../../../../bsps/powerpc/mpc55xxevb/start/irq.c
|
||||
libbsp_a_SOURCES += ../../../../../../bsps/powerpc/mpc55xxevb/start/siu.c
|
||||
|
||||
include $(top_srcdir)/../../../../automake/local.am
|
||||
include $(srcdir)/../../../../../../bsps/powerpc/shared/shared.am
|
||||
|
||||
@@ -167,52 +167,6 @@ endif
|
||||
# END: MPC83XX #
|
||||
##############################################################################
|
||||
|
||||
##############################################################################
|
||||
# START: MPC55XX #
|
||||
##############################################################################
|
||||
if mpc55xx
|
||||
|
||||
# IRQ
|
||||
noinst_PROGRAMS += mpc55xx/irq.rel
|
||||
mpc55xx_irq_rel_SOURCES = mpc55xx/irq/irq.c
|
||||
mpc55xx_irq_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
|
||||
|
||||
# FEC
|
||||
noinst_PROGRAMS += mpc55xx/fec.rel
|
||||
mpc55xx_fec_rel_SOURCES = mpc55xx/fec/fec.c
|
||||
mpc55xx_fec_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
|
||||
|
||||
# eDMA
|
||||
noinst_PROGRAMS += mpc55xx/edma.rel
|
||||
mpc55xx_edma_rel_SOURCES = mpc55xx/edma/edma.c
|
||||
mpc55xx_edma_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
|
||||
|
||||
# eMIOS
|
||||
noinst_PROGRAMS += mpc55xx/emios.rel
|
||||
mpc55xx_emios_rel_SOURCES = mpc55xx/emios/emios.c
|
||||
mpc55xx_emios_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
|
||||
|
||||
# SIU
|
||||
noinst_PROGRAMS += mpc55xx/siu.rel
|
||||
mpc55xx_siu_rel_SOURCES = mpc55xx/siu/siu.c
|
||||
mpc55xx_siu_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
|
||||
|
||||
# DSPI
|
||||
noinst_PROGRAMS += mpc55xx/dspi.rel
|
||||
mpc55xx_dspi_rel_SOURCES = mpc55xx/dspi/dspi.c
|
||||
mpc55xx_dspi_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
|
||||
|
||||
# Misc
|
||||
noinst_PROGRAMS += mpc55xx/misc.rel
|
||||
mpc55xx_misc_rel_SOURCES = mpc55xx/misc/copy.S \
|
||||
mpc55xx/misc/flash_support.c
|
||||
mpc55xx_misc_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
|
||||
|
||||
endif
|
||||
##############################################################################
|
||||
# END: MPC55XX #
|
||||
##############################################################################
|
||||
|
||||
##############################################################################
|
||||
# START: QorIQ #
|
||||
##############################################################################
|
||||
|
||||
@@ -27,7 +27,6 @@ AM_CONDITIONAL(shared, \
|
||||
|| test "$RTEMS_CPU_MODEL" = "mpc7400" \
|
||||
|| test "$RTEMS_CPU_MODEL" = "mpc7455" \
|
||||
|| test "$RTEMS_CPU_MODEL" = "mpc555" \
|
||||
|| test "$RTEMS_CPU_MODEL" = "mpc55xx" \
|
||||
|| test "$RTEMS_CPU_MODEL" = "ppc405" \
|
||||
|| test "$RTEMS_CPU_MODEL" = "ppc440" \
|
||||
|| test "$RTEMS_CPU_MODEL" = "mpc604" \
|
||||
@@ -40,7 +39,6 @@ AM_CONDITIONAL(shared, \
|
||||
|| test "$RTEMS_CPU_MODEL" = "e500")
|
||||
|
||||
# test on CPU type
|
||||
AM_CONDITIONAL(mpc55xx, test "$RTEMS_CPU_MODEL" = "mpc55xx")
|
||||
AM_CONDITIONAL(mpc5xx, test "$RTEMS_CPU_MODEL" = "mpc555" )
|
||||
AM_CONDITIONAL(mpc6xx, test "$RTEMS_CPU_MODEL" = "mpc6xx" \
|
||||
|| test "$RTEMS_CPU_MODEL" = "mpc604" \
|
||||
|
||||
@@ -1,808 +0,0 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @ingroup mpc55xx_dspi
|
||||
*
|
||||
* @brief Source file for the LibI2C bus driver for the Deserial Serial Peripheral Interface (DSPI).
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008
|
||||
* Embedded Brains GmbH
|
||||
* Obere Lagerstr. 30
|
||||
* D-82178 Puchheim
|
||||
* Germany
|
||||
* rtems@embedded-brains.de
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
*/
|
||||
|
||||
#include <mpc55xx/regs.h>
|
||||
#include <mpc55xx/dspi.h>
|
||||
#include <mpc55xx/mpc55xx.h>
|
||||
|
||||
#include <bsp/irq.h>
|
||||
|
||||
#include <libcpu/powerpc-utility.h>
|
||||
|
||||
#define RTEMS_STATUS_CHECKS_USE_PRINTK
|
||||
|
||||
#include <rtems/status-checks.h>
|
||||
|
||||
#define MPC55XX_DSPI_FIFO_SIZE 4
|
||||
|
||||
#define MPC55XX_DSPI_CTAR_NUMBER 8
|
||||
|
||||
#define MPC55XX_DSPI_CTAR_DEFAULT 0
|
||||
|
||||
#define MPC55XX_DSPI_EDMA_MAGIC_SIZE 128
|
||||
|
||||
#define MPC55XX_DSPI_BAUDRATE_SCALER_TABLE_SIZE 63
|
||||
|
||||
typedef struct {
|
||||
uint32_t scaler : 26;
|
||||
uint32_t pbr : 2;
|
||||
uint32_t br : 4;
|
||||
} mpc55xx_dspi_baudrate_scaler_entry;
|
||||
|
||||
static const mpc55xx_dspi_baudrate_scaler_entry mpc55xx_dspi_baudrate_scaler_table [MPC55XX_DSPI_BAUDRATE_SCALER_TABLE_SIZE] = {
|
||||
{ 4, 0, 0 },
|
||||
{ 6, 1, 0 },
|
||||
{ 8, 0, 1 },
|
||||
{ 10, 2, 0 },
|
||||
{ 12, 1, 1 },
|
||||
{ 14, 3, 0 },
|
||||
{ 16, 0, 3 },
|
||||
{ 18, 1, 2 },
|
||||
{ 20, 2, 1 },
|
||||
{ 24, 1, 3 },
|
||||
{ 28, 3, 1 },
|
||||
{ 30, 2, 2 },
|
||||
{ 32, 0, 4 },
|
||||
{ 40, 2, 3 },
|
||||
{ 42, 3, 2 },
|
||||
{ 48, 1, 4 },
|
||||
{ 56, 3, 3 },
|
||||
{ 64, 0, 5 },
|
||||
{ 80, 2, 4 },
|
||||
{ 96, 1, 5 },
|
||||
{ 112, 3, 4 },
|
||||
{ 128, 0, 6 },
|
||||
{ 160, 2, 5 },
|
||||
{ 192, 1, 6 },
|
||||
{ 224, 3, 5 },
|
||||
{ 256, 0, 7 },
|
||||
{ 320, 2, 6 },
|
||||
{ 384, 1, 7 },
|
||||
{ 448, 3, 6 },
|
||||
{ 512, 0, 8 },
|
||||
{ 640, 2, 7 },
|
||||
{ 768, 1, 8 },
|
||||
{ 896, 3, 7 },
|
||||
{ 1024, 0, 9 },
|
||||
{ 1280, 2, 8 },
|
||||
{ 1536, 1, 9 },
|
||||
{ 1792, 3, 8 },
|
||||
{ 2048, 0, 10 },
|
||||
{ 2560, 2, 9 },
|
||||
{ 3072, 1, 10 },
|
||||
{ 3584, 3, 9 },
|
||||
{ 4096, 0, 11 },
|
||||
{ 5120, 2, 10 },
|
||||
{ 6144, 1, 11 },
|
||||
{ 7168, 3, 10 },
|
||||
{ 8192, 0, 12 },
|
||||
{ 10240, 2, 11 },
|
||||
{ 12288, 1, 12 },
|
||||
{ 14336, 3, 11 },
|
||||
{ 16384, 0, 13 },
|
||||
{ 20480, 2, 12 },
|
||||
{ 24576, 1, 13 },
|
||||
{ 28672, 3, 12 },
|
||||
{ 32768, 0, 14 },
|
||||
{ 40960, 2, 13 },
|
||||
{ 49152, 1, 14 },
|
||||
{ 57344, 3, 13 },
|
||||
{ 65536, 0, 15 },
|
||||
{ 81920, 2, 14 },
|
||||
{ 98304, 1, 15 },
|
||||
{ 114688, 3, 14 },
|
||||
{ 163840, 2, 15 },
|
||||
{ 229376, 3, 15 },
|
||||
};
|
||||
|
||||
static void mpc55xx_dspi_edma_done( edma_channel_context *ctx, uint32_t error_status)
|
||||
{
|
||||
const mpc55xx_dspi_edma_entry *e = (const mpc55xx_dspi_edma_entry *) ctx;
|
||||
rtems_semaphore_release( e->id);
|
||||
|
||||
if (error_status != 0) {
|
||||
RTEMS_SYSLOG_ERROR( "eDMA error: 0x%08x\n", error_status);
|
||||
}
|
||||
}
|
||||
|
||||
static mpc55xx_dspi_baudrate_scaler_entry mpc55xx_dspi_search_baudrate_scaler( uint32_t scaler, int min, int mid, int max)
|
||||
{
|
||||
if (scaler <= mpc55xx_dspi_baudrate_scaler_table [mid].scaler) {
|
||||
max = mid;
|
||||
} else {
|
||||
min = mid;
|
||||
}
|
||||
mid = (min + max) / 2;
|
||||
if (mid == min) {
|
||||
return mpc55xx_dspi_baudrate_scaler_table [max];
|
||||
} else {
|
||||
return mpc55xx_dspi_search_baudrate_scaler( scaler, min, mid, max);
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t mpc55xx_dspi_push_data [8 * MPC55XX_DSPI_NUMBER] __attribute__ ((aligned (32)));
|
||||
|
||||
static inline void mpc55xx_dspi_store_push_data( mpc55xx_dspi_bus_entry *e)
|
||||
{
|
||||
mpc55xx_dspi_push_data [e->table_index * 8] = e->push_data.R;
|
||||
rtems_cache_flush_multiple_data_lines( &mpc55xx_dspi_push_data [e->table_index * 8], 4);
|
||||
}
|
||||
|
||||
static inline uint32_t mpc55xx_dspi_push_data_address( mpc55xx_dspi_bus_entry *e)
|
||||
{
|
||||
return (uint32_t) &mpc55xx_dspi_push_data [e->table_index * 8];
|
||||
}
|
||||
|
||||
static inline uint32_t mpc55xx_dspi_nirvana_address( mpc55xx_dspi_bus_entry *e)
|
||||
{
|
||||
return (uint32_t) &mpc55xx_dspi_push_data [e->table_index * 8 + 1];
|
||||
}
|
||||
|
||||
static rtems_status_code mpc55xx_dspi_init( rtems_libi2c_bus_t *bus)
|
||||
{
|
||||
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
||||
mpc55xx_dspi_bus_entry *e = (mpc55xx_dspi_bus_entry *) bus;
|
||||
union DSPI_MCR_tag mcr = MPC55XX_ZERO_FLAGS;
|
||||
union DSPI_CTAR_tag ctar = MPC55XX_ZERO_FLAGS;
|
||||
union DSPI_RSER_tag rser = MPC55XX_ZERO_FLAGS;
|
||||
struct tcd_t tcd_push = EDMA_TCD_DEFAULT;
|
||||
int i = 0;
|
||||
|
||||
/* eDMA receive */
|
||||
sc = rtems_semaphore_create (
|
||||
rtems_build_name ( 'S', 'P', 'I', 'R'),
|
||||
0,
|
||||
RTEMS_SIMPLE_BINARY_SEMAPHORE,
|
||||
0,
|
||||
&e->edma_receive.id
|
||||
);
|
||||
RTEMS_CHECK_SC( sc, "create receive update semaphore");
|
||||
|
||||
sc = mpc55xx_edma_obtain_channel( &e->edma_receive.edma, MPC55XX_INTC_DEFAULT_PRIORITY);
|
||||
RTEMS_CHECK_SC( sc, "obtain receive eDMA channel");
|
||||
|
||||
/* eDMA transmit */
|
||||
sc = rtems_semaphore_create (
|
||||
rtems_build_name ( 'S', 'P', 'I', 'T'),
|
||||
0,
|
||||
RTEMS_SIMPLE_BINARY_SEMAPHORE,
|
||||
0,
|
||||
&e->edma_transmit.id
|
||||
);
|
||||
RTEMS_CHECK_SC( sc, "create transmit update semaphore");
|
||||
|
||||
sc = mpc55xx_edma_obtain_channel( &e->edma_transmit.edma, MPC55XX_INTC_DEFAULT_PRIORITY);
|
||||
RTEMS_CHECK_SC( sc, "obtain transmit eDMA channel");
|
||||
|
||||
sc = mpc55xx_edma_obtain_channel( &e->edma_push.edma, MPC55XX_INTC_DEFAULT_PRIORITY);
|
||||
RTEMS_CHECK_SC( sc, "obtain push eDMA channel");
|
||||
|
||||
tcd_push.SADDR = mpc55xx_dspi_push_data_address( e);
|
||||
tcd_push.SDF.B.SSIZE = 2;
|
||||
tcd_push.SDF.B.SOFF = 0;
|
||||
tcd_push.DADDR = (uint32_t) &e->regs->PUSHR.R;
|
||||
tcd_push.SDF.B.DSIZE = 2;
|
||||
tcd_push.CDF.B.DOFF = 0;
|
||||
tcd_push.NBYTES = 4;
|
||||
tcd_push.CDF.B.CITER = 1;
|
||||
tcd_push.BMF.B.BITER = 1;
|
||||
|
||||
*e->edma_push.edma.edma_tcd = tcd_push;
|
||||
|
||||
/* Module Control Register */
|
||||
mcr.B.MSTR = e->master ? 1 : 0;
|
||||
mcr.B.CONT_SCKE = 0;
|
||||
mcr.B.DCONF = 0;
|
||||
mcr.B.FRZ = 0;
|
||||
mcr.B.MTFE = 0;
|
||||
mcr.B.PCSSE = 0;
|
||||
mcr.B.ROOE = 0;
|
||||
mcr.B.PCSIS0 = 1;
|
||||
mcr.B.PCSIS1 = 1;
|
||||
mcr.B.PCSIS2 = 1;
|
||||
mcr.B.PCSIS3 = 1;
|
||||
mcr.B.PCSIS5 = 1;
|
||||
mcr.B.MDIS = 0;
|
||||
mcr.B.DIS_TXF = 0;
|
||||
mcr.B.DIS_RXF = 0;
|
||||
mcr.B.CLR_TXF = 0;
|
||||
mcr.B.CLR_RXF = 0;
|
||||
mcr.B.SMPL_PT = 0;
|
||||
mcr.B.HALT = 0;
|
||||
|
||||
e->regs->MCR.R = mcr.R;
|
||||
|
||||
/* Clock and Transfer Attributes Register */
|
||||
ctar.B.DBR = 0;
|
||||
ctar.B.FMSZ = 0x7;
|
||||
ctar.B.CPOL = 0;
|
||||
ctar.B.CPHA = 0;
|
||||
ctar.B.LSBFE = 0;
|
||||
ctar.B.PCSSCK = 0;
|
||||
ctar.B.PASC = 0;
|
||||
ctar.B.PDT = 0;
|
||||
ctar.B.PBR = 0;
|
||||
ctar.B.CSSCK = 0;
|
||||
ctar.B.ASC = 0;
|
||||
ctar.B.DT = 0;
|
||||
ctar.B.BR = 0;
|
||||
|
||||
for (i = 0; i < MPC55XX_DSPI_CTAR_NUMBER; ++i) {
|
||||
e->regs->CTAR [i].R = ctar.R;
|
||||
}
|
||||
|
||||
/* DMA/Interrupt Request Select and Enable Register */
|
||||
rser.B.TFFFRE = 1;
|
||||
rser.B.TFFFDIRS = 1;
|
||||
rser.B.RFDFRE = 1;
|
||||
rser.B.RFDFDIRS = 1;
|
||||
|
||||
e->regs->RSER.R = rser.R;
|
||||
|
||||
return RTEMS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
static rtems_status_code mpc55xx_dspi_send_start( rtems_libi2c_bus_t *bus)
|
||||
{
|
||||
mpc55xx_dspi_bus_entry *e = (mpc55xx_dspi_bus_entry *) bus;
|
||||
|
||||
/* Reset chip selects */
|
||||
e->push_data.B.PCS0 = 0;
|
||||
e->push_data.B.PCS1 = 0;
|
||||
e->push_data.B.PCS2 = 0;
|
||||
e->push_data.B.PCS3 = 0;
|
||||
e->push_data.B.PCS4 = 0;
|
||||
e->push_data.B.PCS5 = 0;
|
||||
mpc55xx_dspi_store_push_data( e);
|
||||
|
||||
return RTEMS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
static rtems_status_code mpc55xx_dspi_send_stop( rtems_libi2c_bus_t *bus)
|
||||
{
|
||||
return RTEMS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
static rtems_status_code mpc55xx_dspi_send_addr( rtems_libi2c_bus_t *bus, uint32_t addr, int rw)
|
||||
{
|
||||
mpc55xx_dspi_bus_entry *e = (mpc55xx_dspi_bus_entry *) bus;
|
||||
union DSPI_SR_tag sr = MPC55XX_ZERO_FLAGS;
|
||||
|
||||
/* Flush transmit and receive FIFO */
|
||||
e->regs->MCR.B.CLR_TXF = 1;
|
||||
e->regs->MCR.B.CLR_RXF = 1;
|
||||
|
||||
/* Clear status flags */
|
||||
sr.B.EOQF = 1;
|
||||
sr.B.TFFF = 1;
|
||||
sr.B.RFDF = 1;
|
||||
e->regs->SR.R = sr.R;
|
||||
|
||||
/* Frame command */
|
||||
e->push_data.R = 0;
|
||||
e->push_data.B.CONT = 0;
|
||||
e->push_data.B.CTAS = MPC55XX_DSPI_CTAR_DEFAULT;
|
||||
e->push_data.B.EOQ = 0;
|
||||
e->push_data.B.CTCNT = 0;
|
||||
switch (addr) {
|
||||
case 0:
|
||||
e->push_data.B.PCS0 = 1;
|
||||
break;
|
||||
case 1:
|
||||
e->push_data.B.PCS1 = 1;
|
||||
break;
|
||||
case 2:
|
||||
e->push_data.B.PCS2 = 1;
|
||||
break;
|
||||
case 3:
|
||||
e->push_data.B.PCS3 = 1;
|
||||
break;
|
||||
case 4:
|
||||
e->push_data.B.PCS4 = 1;
|
||||
break;
|
||||
case 5:
|
||||
e->push_data.B.PCS5 = 1;
|
||||
break;
|
||||
default:
|
||||
return -RTEMS_INVALID_ADDRESS;
|
||||
}
|
||||
mpc55xx_dspi_store_push_data( e);
|
||||
|
||||
return RTEMS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
/* FIXME, TODO */
|
||||
extern uint32_t bsp_clock_speed;
|
||||
|
||||
static int mpc55xx_dspi_set_transfer_mode( rtems_libi2c_bus_t *bus, const rtems_libi2c_tfr_mode_t *mode)
|
||||
{
|
||||
mpc55xx_dspi_bus_entry *e = (mpc55xx_dspi_bus_entry *) bus;
|
||||
union DSPI_CTAR_tag ctar = MPC55XX_ZERO_FLAGS;
|
||||
|
||||
if (mode->bits_per_char != 8) {
|
||||
return -RTEMS_INVALID_NUMBER;
|
||||
}
|
||||
|
||||
e->idle_char = mode->idle_char;
|
||||
|
||||
ctar.R = e->regs->CTAR [MPC55XX_DSPI_CTAR_DEFAULT].R;
|
||||
|
||||
ctar.B.PCSSCK = 0;
|
||||
ctar.B.CSSCK = 0;
|
||||
ctar.B.PASC = 0;
|
||||
ctar.B.ASC = 0;
|
||||
|
||||
ctar.B.LSBFE = mode->lsb_first ? 1 : 0;
|
||||
ctar.B.CPOL = mode->clock_inv ? 1 : 0;
|
||||
ctar.B.CPHA = mode->clock_phs ? 1 : 0;
|
||||
|
||||
if (mode->baudrate != e->baud) {
|
||||
uint32_t scaler = bsp_clock_speed / mode->baudrate;
|
||||
mpc55xx_dspi_baudrate_scaler_entry bse = mpc55xx_dspi_search_baudrate_scaler( scaler, 0, MPC55XX_DSPI_BAUDRATE_SCALER_TABLE_SIZE / 2, MPC55XX_DSPI_BAUDRATE_SCALER_TABLE_SIZE);
|
||||
|
||||
ctar.B.PBR = bse.pbr;
|
||||
ctar.B.BR = bse.br;
|
||||
|
||||
e->baud = mode->baudrate;
|
||||
}
|
||||
|
||||
e->regs->CTAR [MPC55XX_DSPI_CTAR_DEFAULT].R = ctar.R;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Writes @a n characters from @a out to bus @a bus and synchronously stores the received data in @a in.
|
||||
*
|
||||
* eDMA channel usage for transmission:
|
||||
* @dot
|
||||
* digraph push {
|
||||
* push [label="Push Register"];
|
||||
* push_data [label="Push Data"];
|
||||
* idle_push_data [label="Idle Push Data"];
|
||||
* out [shape=box,label="Output Buffer"];
|
||||
* edge [color=red,fontcolor=red];
|
||||
* push -> idle_push_data [label="Transmit Request",URL="\ref mpc55xx_dspi_bus_entry::edma_transmit"];
|
||||
* push -> out [label="Transmit Request",URL="\ref mpc55xx_dspi_bus_entry::edma_transmit"];
|
||||
* out -> push_data [label="Channel Link",URL="\ref mpc55xx_dspi_bus_entry::edma_push"];
|
||||
* edge [color=blue,fontcolor=blue];
|
||||
* out -> push_data [label="Data"];
|
||||
* push_data -> push [label="Data"];
|
||||
* idle_push_data -> push [label="Data"];
|
||||
* }
|
||||
* @enddot
|
||||
*
|
||||
* eDMA channel usage for receiving:
|
||||
* @dot
|
||||
* digraph pop {
|
||||
* pop [label="Pop Register"];
|
||||
* nirvana [label="Nirvana"];
|
||||
* in [shape=box,label="Input Buffer"];
|
||||
* edge [color=red,fontcolor=red];
|
||||
* pop -> nirvana [label="Receive Request",URL="\ref mpc55xx_dspi_bus_entry::edma_receive"];
|
||||
* pop -> in [label="Receive Request",URL="\ref mpc55xx_dspi_bus_entry::edma_receive"];
|
||||
* edge [color=blue,fontcolor=blue];
|
||||
* pop -> nirvana [label="Data"];
|
||||
* pop -> in [label="Data"];
|
||||
* }
|
||||
* @enddot
|
||||
*/
|
||||
static int mpc55xx_dspi_read_write( rtems_libi2c_bus_t *bus, unsigned char *in, const unsigned char *out, int n)
|
||||
{
|
||||
mpc55xx_dspi_bus_entry *e = (mpc55xx_dspi_bus_entry *) bus;
|
||||
|
||||
/* Non cache aligned characters */
|
||||
int n_nc = n;
|
||||
|
||||
/* Cache aligned characters */
|
||||
int n_c = 0;
|
||||
|
||||
/* Register addresses */
|
||||
volatile void *push = &e->regs->PUSHR.R;
|
||||
volatile void *pop = &e->regs->POPR.R;
|
||||
volatile union DSPI_SR_tag *status = &e->regs->SR;
|
||||
|
||||
/* Push and pop data */
|
||||
union DSPI_PUSHR_tag push_data = e->push_data;
|
||||
union DSPI_POPR_tag pop_data;
|
||||
|
||||
/* Status register */
|
||||
union DSPI_SR_tag sr;
|
||||
|
||||
/* Read and write indices */
|
||||
int r = 0;
|
||||
int w = 0;
|
||||
|
||||
if (n == 0) {
|
||||
return 0;
|
||||
} else if (in == NULL && out == NULL) {
|
||||
return -RTEMS_INVALID_ADDRESS;
|
||||
}
|
||||
|
||||
if (n > MPC55XX_DSPI_EDMA_MAGIC_SIZE) {
|
||||
n_nc = (int) mpc55xx_non_cache_aligned_size( in);
|
||||
n_c = (int) mpc55xx_cache_aligned_size( in, (size_t) n);
|
||||
if (n_c > EDMA_TCD_BITER_LINKED_SIZE) {
|
||||
RTEMS_SYSLOG_WARNING( "buffer size out of range, cannot use eDMA\n");
|
||||
n_nc = n;
|
||||
n_c = 0;
|
||||
} else if (n_nc + n_c != n) {
|
||||
RTEMS_SYSLOG_WARNING( "input buffer not proper cache aligned, cannot use eDMA\n");
|
||||
n_nc = n;
|
||||
n_c = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if (e->regs->SR.B.TXCTR != e->regs->SR.B.RXCTR) {
|
||||
RTEMS_SYSLOG_WARNING( "FIFO counter not equal\n");
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
|
||||
/* Direct IO */
|
||||
if (out == NULL) {
|
||||
push_data.B.TXDATA = e->idle_char;
|
||||
while (r < n_nc || w < n_nc) {
|
||||
/* Wait for available FIFO */
|
||||
do {
|
||||
sr.R = status->R;
|
||||
} while (sr.B.TXCTR == MPC55XX_DSPI_FIFO_SIZE && sr.B.RXCTR == 0);
|
||||
|
||||
/* Write */
|
||||
if (w < n_nc && (w - r) < MPC55XX_DSPI_FIFO_SIZE && sr.B.TXCTR != MPC55XX_DSPI_FIFO_SIZE) {
|
||||
++w;
|
||||
ppc_write_word( push_data.R, push);
|
||||
}
|
||||
|
||||
/* Read */
|
||||
if (r < n_nc && sr.B.RXCTR != 0) {
|
||||
pop_data.R = ppc_read_word( pop);
|
||||
in [r] = (unsigned char) pop_data.B.RXDATA;
|
||||
++r;
|
||||
}
|
||||
}
|
||||
} else if (in == NULL) {
|
||||
while (r < n_nc || w < n_nc) {
|
||||
/* Wait for available FIFO */
|
||||
do {
|
||||
sr.R = status->R;
|
||||
} while (sr.B.TXCTR == MPC55XX_DSPI_FIFO_SIZE && sr.B.RXCTR == 0);
|
||||
|
||||
/* Write */
|
||||
if (w < n_nc && (w - r) < MPC55XX_DSPI_FIFO_SIZE && sr.B.TXCTR != MPC55XX_DSPI_FIFO_SIZE) {
|
||||
push_data.B.TXDATA = out [w];
|
||||
++w;
|
||||
ppc_write_word( push_data.R, push);
|
||||
}
|
||||
|
||||
/* Read */
|
||||
if (r < n_nc && sr.B.RXCTR != 0) {
|
||||
pop_data.R = ppc_read_word( pop);
|
||||
++r;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
while (r < n_nc || w < n_nc) {
|
||||
/* Wait for available FIFO */
|
||||
do {
|
||||
sr.R = status->R;
|
||||
} while (sr.B.TXCTR == MPC55XX_DSPI_FIFO_SIZE && sr.B.RXCTR == 0);
|
||||
|
||||
/* Write */
|
||||
if (w < n_nc && (w - r) < MPC55XX_DSPI_FIFO_SIZE && sr.B.TXCTR != MPC55XX_DSPI_FIFO_SIZE) {
|
||||
push_data.B.TXDATA = out [w];
|
||||
++w;
|
||||
ppc_write_word( push_data.R, push);
|
||||
}
|
||||
|
||||
/* Read */
|
||||
if (r < n_nc && sr.B.RXCTR != 0) {
|
||||
pop_data.R = ppc_read_word( pop);
|
||||
in [r] = (unsigned char) pop_data.B.RXDATA;
|
||||
++r;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* eDMA transfers */
|
||||
if (n_c > 0) {
|
||||
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
||||
unsigned char *in_c = in + n_nc;
|
||||
const unsigned char *out_c = out + n_nc;
|
||||
struct tcd_t tcd_transmit = EDMA_TCD_DEFAULT;
|
||||
struct tcd_t tcd_receive = EDMA_TCD_DEFAULT;
|
||||
|
||||
/* Cache operations */
|
||||
rtems_cache_flush_multiple_data_lines( out_c, (size_t) n_c);
|
||||
rtems_cache_invalidate_multiple_data_lines( in_c, (size_t) n_c);
|
||||
|
||||
/* Set transmit TCD */
|
||||
if (out == NULL) {
|
||||
e->push_data.B.TXDATA = e->idle_char;
|
||||
mpc55xx_dspi_store_push_data( e);
|
||||
tcd_transmit.SADDR = mpc55xx_dspi_push_data_address( e);
|
||||
tcd_transmit.SDF.B.SSIZE = 2;
|
||||
tcd_transmit.SDF.B.SOFF = 0;
|
||||
tcd_transmit.DADDR = (uint32_t) push;
|
||||
tcd_transmit.SDF.B.DSIZE = 2;
|
||||
tcd_transmit.CDF.B.DOFF = 0;
|
||||
tcd_transmit.NBYTES = 4;
|
||||
tcd_transmit.CDF.B.CITER = n_c;
|
||||
tcd_transmit.BMF.B.BITER = n_c;
|
||||
} else {
|
||||
unsigned push_channel = mpc55xx_edma_channel_by_tcd( e->edma_push.edma.edma_tcd);
|
||||
mpc55xx_edma_clear_done( e->edma_transmit.edma.edma_tcd);
|
||||
tcd_transmit.SADDR = (uint32_t) out_c;
|
||||
tcd_transmit.SDF.B.SSIZE = 0;
|
||||
tcd_transmit.SDF.B.SOFF = 1;
|
||||
tcd_transmit.DADDR = mpc55xx_dspi_push_data_address( e) + 3;
|
||||
tcd_transmit.SDF.B.DSIZE = 0;
|
||||
tcd_transmit.CDF.B.DOFF = 0;
|
||||
tcd_transmit.NBYTES = 1;
|
||||
tcd_transmit.CDF.B.CITERE_LINK = 1;
|
||||
tcd_transmit.BMF.B.BITERE_LINK = 1;
|
||||
tcd_transmit.BMF.B.MAJORLINKCH = push_channel;
|
||||
tcd_transmit.CDF.B.CITER = EDMA_TCD_LINK_AND_BITER( push_channel, n_c);
|
||||
tcd_transmit.BMF.B.BITER = EDMA_TCD_LINK_AND_BITER( push_channel, n_c);
|
||||
tcd_transmit.BMF.B.MAJORE_LINK = 1;
|
||||
}
|
||||
tcd_transmit.BMF.B.D_REQ = 1;
|
||||
tcd_transmit.BMF.B.INT_MAJ = 1;
|
||||
*e->edma_transmit.edma.edma_tcd = tcd_transmit;
|
||||
|
||||
/* Set receive TCD */
|
||||
if (in == NULL) {
|
||||
tcd_receive.CDF.B.DOFF = 0;
|
||||
tcd_receive.DADDR = mpc55xx_dspi_nirvana_address( e);
|
||||
} else {
|
||||
tcd_receive.CDF.B.DOFF = 1;
|
||||
tcd_receive.DADDR = (uint32_t) in_c;
|
||||
}
|
||||
tcd_receive.SADDR = (uint32_t) pop + 3;
|
||||
tcd_receive.SDF.B.SSIZE = 0;
|
||||
tcd_receive.SDF.B.SOFF = 0;
|
||||
tcd_receive.SDF.B.DSIZE = 0;
|
||||
tcd_receive.NBYTES = 1;
|
||||
tcd_receive.BMF.B.D_REQ = 1;
|
||||
tcd_receive.BMF.B.INT_MAJ = 1;
|
||||
tcd_receive.CDF.B.CITER = n_c;
|
||||
tcd_receive.BMF.B.BITER = n_c;
|
||||
*e->edma_receive.edma.edma_tcd = tcd_receive;
|
||||
|
||||
/* Clear request flags */
|
||||
sr.R = 0;
|
||||
sr.B.TFFF = 1;
|
||||
sr.B.RFDF = 1;
|
||||
status->R = sr.R;
|
||||
|
||||
/* Enable hardware requests */
|
||||
mpc55xx_edma_enable_hardware_requests( e->edma_receive.edma.edma_tcd);
|
||||
mpc55xx_edma_enable_hardware_requests( e->edma_transmit.edma.edma_tcd);
|
||||
|
||||
/* Wait for transmit update */
|
||||
sc = rtems_semaphore_obtain( e->edma_transmit.id, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
|
||||
RTEMS_CHECK_SC_RV( sc, "transmit update");
|
||||
|
||||
/* Wait for receive update */
|
||||
sc = rtems_semaphore_obtain( e->edma_receive.id, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
|
||||
RTEMS_CHECK_SC_RV( sc, "receive update");
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reads @a n characters from bus @a bus and stores it in @a in.
|
||||
*
|
||||
* Writes idle characters to receive data.
|
||||
*
|
||||
* @see mpc55xx_dspi_read_write().
|
||||
*/
|
||||
static int mpc55xx_dspi_read( rtems_libi2c_bus_t *bus, unsigned char *in, int n)
|
||||
{
|
||||
return mpc55xx_dspi_read_write( bus, in, NULL, n);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Writes @a n characters from @a out to bus @a bus.
|
||||
*
|
||||
* Discards the synchronously received data.
|
||||
*
|
||||
* @see mpc55xx_dspi_read_write().
|
||||
*/
|
||||
static int mpc55xx_dspi_write( rtems_libi2c_bus_t *bus, unsigned char *out, int n)
|
||||
{
|
||||
return mpc55xx_dspi_read_write( bus, NULL, out, n);
|
||||
}
|
||||
|
||||
static int mpc55xx_dspi_ioctl( rtems_libi2c_bus_t *bus, int cmd, void *arg)
|
||||
{
|
||||
int rv = -1;
|
||||
switch (cmd) {
|
||||
case RTEMS_LIBI2C_IOCTL_SET_TFRMODE:
|
||||
rv = mpc55xx_dspi_set_transfer_mode( bus, (const rtems_libi2c_tfr_mode_t *) arg);
|
||||
break;
|
||||
case RTEMS_LIBI2C_IOCTL_READ_WRITE:
|
||||
rv = mpc55xx_dspi_read_write(
|
||||
bus,
|
||||
((rtems_libi2c_read_write_t *) arg)->rd_buf,
|
||||
((rtems_libi2c_read_write_t *) arg)->wr_buf,
|
||||
((rtems_libi2c_read_write_t *) arg)->byte_cnt
|
||||
);
|
||||
break;
|
||||
default:
|
||||
rv = -RTEMS_NOT_DEFINED;
|
||||
break;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
static const rtems_libi2c_bus_ops_t mpc55xx_dspi_ops = {
|
||||
.init = mpc55xx_dspi_init,
|
||||
.send_start = mpc55xx_dspi_send_start,
|
||||
.send_stop = mpc55xx_dspi_send_stop,
|
||||
.send_addr = mpc55xx_dspi_send_addr,
|
||||
.read_bytes = mpc55xx_dspi_read,
|
||||
.write_bytes = mpc55xx_dspi_write,
|
||||
.ioctl = mpc55xx_dspi_ioctl
|
||||
};
|
||||
|
||||
mpc55xx_dspi_bus_entry mpc55xx_dspi_bus_table [MPC55XX_DSPI_NUMBER] = {
|
||||
{
|
||||
/* DSPI A */
|
||||
.bus = {
|
||||
.ops = &mpc55xx_dspi_ops,
|
||||
.size = sizeof( mpc55xx_dspi_bus_entry)
|
||||
},
|
||||
.table_index = 0,
|
||||
.bus_number = 0,
|
||||
.regs = &DSPI_A,
|
||||
.master = true,
|
||||
.push_data = MPC55XX_ZERO_FLAGS,
|
||||
.edma_transmit = {
|
||||
.edma = {
|
||||
.edma_tcd = EDMA_TCD_BY_CHANNEL_INDEX(EDMA_DSPI_A_SR_TFFF),
|
||||
.done = mpc55xx_dspi_edma_done
|
||||
},
|
||||
.id = RTEMS_ID_NONE
|
||||
},
|
||||
.edma_push = {
|
||||
.edma = {
|
||||
.edma_tcd = &EDMA.TCD [43],
|
||||
.done = mpc55xx_dspi_edma_done
|
||||
},
|
||||
.id = RTEMS_ID_NONE
|
||||
},
|
||||
.edma_receive = {
|
||||
.edma = {
|
||||
.edma_tcd = EDMA_TCD_BY_CHANNEL_INDEX(EDMA_DSPI_A_SR_RFDF),
|
||||
.done = mpc55xx_dspi_edma_done
|
||||
},
|
||||
.id = RTEMS_ID_NONE
|
||||
},
|
||||
.idle_char = 0xffffffff,
|
||||
.baud = 0
|
||||
}, {
|
||||
/* DSPI B */
|
||||
.bus = {
|
||||
.ops = &mpc55xx_dspi_ops,
|
||||
.size = sizeof( mpc55xx_dspi_bus_entry)
|
||||
},
|
||||
.table_index = 1,
|
||||
.bus_number = 0,
|
||||
.regs = &DSPI_B,
|
||||
.master = true,
|
||||
.push_data = MPC55XX_ZERO_FLAGS,
|
||||
.edma_transmit = {
|
||||
.edma = {
|
||||
.edma_tcd = EDMA_TCD_BY_CHANNEL_INDEX(EDMA_DSPI_B_SR_TFFF),
|
||||
.done = mpc55xx_dspi_edma_done
|
||||
},
|
||||
.id = RTEMS_ID_NONE
|
||||
},
|
||||
.edma_push = {
|
||||
.edma = {
|
||||
.edma_tcd = &EDMA.TCD [10],
|
||||
.done = mpc55xx_dspi_edma_done
|
||||
},
|
||||
.id = RTEMS_ID_NONE
|
||||
},
|
||||
.edma_receive = {
|
||||
.edma = {
|
||||
.edma_tcd = EDMA_TCD_BY_CHANNEL_INDEX(EDMA_DSPI_B_SR_RFDF),
|
||||
.done = mpc55xx_dspi_edma_done
|
||||
},
|
||||
.id = RTEMS_ID_NONE
|
||||
},
|
||||
.idle_char = 0xffffffff,
|
||||
.baud = 0
|
||||
}, {
|
||||
/* DSPI C */
|
||||
.bus = {
|
||||
.ops = &mpc55xx_dspi_ops,
|
||||
.size = sizeof( mpc55xx_dspi_bus_entry)
|
||||
},
|
||||
.table_index = 2,
|
||||
.bus_number = 0,
|
||||
.regs = &DSPI_C,
|
||||
.master = true,
|
||||
.push_data = MPC55XX_ZERO_FLAGS,
|
||||
.edma_transmit = {
|
||||
.edma = {
|
||||
.edma_tcd = EDMA_TCD_BY_CHANNEL_INDEX(EDMA_DSPI_C_SR_TFFF),
|
||||
.done = mpc55xx_dspi_edma_done
|
||||
},
|
||||
.id = RTEMS_ID_NONE
|
||||
},
|
||||
.edma_push = {
|
||||
.edma = {
|
||||
.edma_tcd = &EDMA.TCD [11],
|
||||
.done = mpc55xx_dspi_edma_done
|
||||
},
|
||||
.id = RTEMS_ID_NONE
|
||||
},
|
||||
.edma_receive = {
|
||||
.edma = {
|
||||
.edma_tcd = EDMA_TCD_BY_CHANNEL_INDEX(EDMA_DSPI_C_SR_RFDF),
|
||||
.done = mpc55xx_dspi_edma_done
|
||||
},
|
||||
.id = RTEMS_ID_NONE
|
||||
},
|
||||
.idle_char = 0xffffffff,
|
||||
.baud = 0
|
||||
#ifdef DSPI_D
|
||||
}, {
|
||||
/* DSPI D */
|
||||
.bus = {
|
||||
.ops = &mpc55xx_dspi_ops,
|
||||
.size = sizeof( mpc55xx_dspi_bus_entry)
|
||||
},
|
||||
.table_index = 3,
|
||||
.bus_number = 0,
|
||||
.regs = &DSPI_D,
|
||||
.master = true,
|
||||
.push_data = MPC55XX_ZERO_FLAGS,
|
||||
.edma_transmit = {
|
||||
.edma = {
|
||||
.edma_tcd = EDMA_TCD_BY_CHANNEL_INDEX(EDMA_DSPI_D_SR_TFFF),
|
||||
.done = mpc55xx_dspi_edma_done
|
||||
},
|
||||
.id = RTEMS_ID_NONE
|
||||
},
|
||||
.edma_push = {
|
||||
.edma = {
|
||||
.edma_tcd = &EDMA.TCD [18],
|
||||
.done = mpc55xx_dspi_edma_done
|
||||
},
|
||||
.id = RTEMS_ID_NONE
|
||||
},
|
||||
.edma_receive = {
|
||||
.edma = {
|
||||
.edma_tcd = EDMA_TCD_BY_CHANNEL_INDEX(EDMA_DSPI_D_SR_RFDF),
|
||||
.done = mpc55xx_dspi_edma_done
|
||||
},
|
||||
.id = RTEMS_ID_NONE
|
||||
},
|
||||
.idle_char = 0xffffffff,
|
||||
.baud = 0
|
||||
#endif
|
||||
}
|
||||
};
|
||||
@@ -1,329 +0,0 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @ingroup mpc55xx
|
||||
*
|
||||
* @brief Enhanced Direct Memory Access (eDMA).
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008-2013 embedded brains GmbH. All rights reserved.
|
||||
*
|
||||
* embedded brains GmbH
|
||||
* Dornierstr. 4
|
||||
* 82178 Puchheim
|
||||
* Germany
|
||||
* <rtems@embedded-brains.de>
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
*/
|
||||
|
||||
#include <mpc55xx/edma.h>
|
||||
#include <mpc55xx/mpc55xx.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include <bsp.h>
|
||||
#include <bsp/fatal.h>
|
||||
#include <bsp/irq.h>
|
||||
|
||||
#define EDMA_CHANNELS_PER_GROUP 32U
|
||||
|
||||
#define EDMA_GROUP_COUNT ((EDMA_CHANNEL_COUNT + 31U) / 32U)
|
||||
|
||||
#define EDMA_GROUP_INDEX(channel) ((channel) / EDMA_CHANNELS_PER_GROUP)
|
||||
|
||||
#define EDMA_GROUP_BIT(channel) (1U << ((channel) % EDMA_CHANNELS_PER_GROUP))
|
||||
|
||||
#define EDMA_MODULE_INDEX(channel) ((channel) / EDMA_CHANNELS_PER_MODULE)
|
||||
|
||||
static uint32_t edma_channel_occupation [EDMA_GROUP_COUNT];
|
||||
|
||||
static RTEMS_CHAIN_DEFINE_EMPTY(edma_channel_chain);
|
||||
|
||||
static unsigned edma_channel_index_of_tcd(volatile struct tcd_t *edma_tcd)
|
||||
{
|
||||
volatile struct EDMA_tag *edma = mpc55xx_edma_by_tcd(edma_tcd);
|
||||
unsigned channel = edma_tcd - &edma->TCD[0];
|
||||
|
||||
#if EDMA_MODULE_COUNT == 1
|
||||
return channel;
|
||||
#elif EDMA_MODULE_COUNT == 2
|
||||
return channel + (&EDMA_A == edma ? 0 : EDMA_CHANNELS_PER_MODULE);
|
||||
#else
|
||||
#error "unsupported module count"
|
||||
#endif
|
||||
}
|
||||
|
||||
static volatile struct EDMA_tag *edma_get_regs_by_module(unsigned module)
|
||||
{
|
||||
#if EDMA_MODULE_COUNT == 1
|
||||
return &EDMA;
|
||||
#elif EDMA_MODULE_COUNT == 2
|
||||
return module == 0 ? &EDMA_A : &EDMA_B;
|
||||
#else
|
||||
#error "unsupported module count"
|
||||
#endif
|
||||
}
|
||||
|
||||
static uint32_t edma_bit_array_set(unsigned channel, uint32_t *bit_array)
|
||||
{
|
||||
unsigned array = channel / 32;
|
||||
uint32_t bit = 1U << (channel % 32);
|
||||
uint32_t previous = bit_array [array];
|
||||
|
||||
bit_array [array] = previous | bit;
|
||||
|
||||
return previous;
|
||||
}
|
||||
|
||||
static uint32_t edma_bit_array_clear(unsigned channel, uint32_t *bit_array)
|
||||
{
|
||||
unsigned array = channel / 32;
|
||||
uint32_t bit = 1U << (channel % 32);
|
||||
uint32_t previous = bit_array [array];
|
||||
|
||||
bit_array [array] = previous & ~bit;
|
||||
|
||||
return previous;
|
||||
}
|
||||
|
||||
static void edma_interrupt_handler(void *arg)
|
||||
{
|
||||
edma_channel_context *ctx = arg;
|
||||
|
||||
mpc55xx_edma_clear_interrupts(ctx->edma_tcd);
|
||||
|
||||
(*ctx->done)(ctx, 0);
|
||||
}
|
||||
|
||||
static void edma_interrupt_error_handler(void *arg)
|
||||
{
|
||||
rtems_chain_control *chain = &edma_channel_chain;
|
||||
rtems_chain_node *node = rtems_chain_first(chain);
|
||||
uint32_t error_channels [] = {
|
||||
#if EDMA_GROUP_COUNT >= 1
|
||||
EDMA.ERL.R
|
||||
#endif
|
||||
#if EDMA_GROUP_COUNT >= 2
|
||||
, EDMA.ERH.R
|
||||
#endif
|
||||
#if EDMA_GROUP_COUNT >= 3
|
||||
, EDMA_B.ERL.R
|
||||
#endif
|
||||
};
|
||||
uint32_t error_status [] = {
|
||||
#if EDMA_GROUP_COUNT >= 1
|
||||
EDMA.ESR.R
|
||||
#endif
|
||||
#if EDMA_GROUP_COUNT >= 3
|
||||
, EDMA_B.ESR.R
|
||||
#endif
|
||||
};
|
||||
|
||||
#if EDMA_GROUP_COUNT >= 1
|
||||
EDMA.ERL.R = error_channels [0];
|
||||
#endif
|
||||
#if EDMA_GROUP_COUNT >= 2
|
||||
EDMA.ERH.R = error_channels [1];
|
||||
#endif
|
||||
#if EDMA_GROUP_COUNT >= 3
|
||||
EDMA_B.ERL.R = error_channels [2];
|
||||
#endif
|
||||
|
||||
while (!rtems_chain_is_tail(chain, node)) {
|
||||
edma_channel_context *ctx = (edma_channel_context *) node;
|
||||
unsigned channel_index = edma_channel_index_of_tcd(ctx->edma_tcd);
|
||||
unsigned group_index = EDMA_GROUP_INDEX(channel_index);
|
||||
unsigned group_bit = EDMA_GROUP_BIT(channel_index);
|
||||
|
||||
if ((error_channels [group_index] & group_bit) != 0) {
|
||||
unsigned module_index = EDMA_MODULE_INDEX(channel_index);
|
||||
|
||||
(*ctx->done)(ctx, error_status [module_index]);
|
||||
}
|
||||
|
||||
node = rtems_chain_next(node);
|
||||
}
|
||||
}
|
||||
|
||||
void mpc55xx_edma_init(void)
|
||||
{
|
||||
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
||||
unsigned channel_remaining = EDMA_CHANNEL_COUNT;
|
||||
unsigned module = 0;
|
||||
unsigned group = 0;
|
||||
|
||||
for (module = 0; module < EDMA_MODULE_COUNT; ++module) {
|
||||
volatile struct EDMA_tag *edma = edma_get_regs_by_module(module);
|
||||
unsigned channel_count = channel_remaining < EDMA_CHANNELS_PER_MODULE ?
|
||||
channel_remaining : EDMA_CHANNELS_PER_MODULE;
|
||||
unsigned channel = 0;
|
||||
|
||||
channel_remaining -= channel_count;
|
||||
|
||||
/* Disable requests */
|
||||
edma->CERQR.B.CERQ = 0x40;
|
||||
|
||||
/* Arbitration mode: group round robin, channel fixed */
|
||||
edma->CR.B.ERGA = 1;
|
||||
edma->CR.B.ERCA = 0;
|
||||
for (channel = 0; channel < channel_count; ++channel) {
|
||||
volatile struct tcd_t *tcd = &edma->TCD [channel];
|
||||
edma->CPR [channel].R = 0x80U | (channel & 0xfU);
|
||||
|
||||
/* Initialize TCD, stop channel first */
|
||||
tcd->BMF.R = 0;
|
||||
tcd->SADDR = 0;
|
||||
tcd->SDF.R = 0;
|
||||
tcd->NBYTES = 0;
|
||||
tcd->SLAST = 0;
|
||||
tcd->DADDR = 0;
|
||||
tcd->CDF.R = 0;
|
||||
tcd->DLAST_SGA = 0;
|
||||
}
|
||||
|
||||
/* Clear interrupt requests */
|
||||
edma->CIRQR.B.CINT = 0x40;
|
||||
edma->CER.B.CERR = 0x40;
|
||||
}
|
||||
|
||||
for (group = 0; group < EDMA_GROUP_COUNT; ++group) {
|
||||
sc = mpc55xx_interrupt_handler_install(
|
||||
MPC55XX_IRQ_EDMA_ERROR(group),
|
||||
"eDMA Error",
|
||||
RTEMS_INTERRUPT_UNIQUE,
|
||||
MPC55XX_INTC_DEFAULT_PRIORITY,
|
||||
edma_interrupt_error_handler,
|
||||
NULL
|
||||
);
|
||||
if (sc != RTEMS_SUCCESSFUL) {
|
||||
bsp_fatal(MPC55XX_FATAL_EDMA_IRQ_INSTALL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rtems_status_code mpc55xx_edma_obtain_channel_by_tcd(
|
||||
volatile struct tcd_t *edma_tcd
|
||||
)
|
||||
{
|
||||
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
||||
unsigned channel_index = edma_channel_index_of_tcd(edma_tcd);
|
||||
rtems_interrupt_level level;
|
||||
uint32_t channel_occupation;
|
||||
|
||||
rtems_interrupt_disable(level);
|
||||
channel_occupation = edma_bit_array_set(
|
||||
channel_index,
|
||||
&edma_channel_occupation [0]
|
||||
);
|
||||
rtems_interrupt_enable(level);
|
||||
|
||||
if ((channel_occupation & EDMA_GROUP_BIT(channel_index)) != 0) {
|
||||
sc = RTEMS_RESOURCE_IN_USE;
|
||||
}
|
||||
|
||||
return sc;
|
||||
}
|
||||
|
||||
void mpc55xx_edma_release_channel_by_tcd(volatile struct tcd_t *edma_tcd)
|
||||
{
|
||||
unsigned channel_index = edma_channel_index_of_tcd(edma_tcd);
|
||||
rtems_interrupt_level level;
|
||||
|
||||
rtems_interrupt_disable(level);
|
||||
edma_bit_array_clear(channel_index, &edma_channel_occupation [0]);
|
||||
rtems_interrupt_enable(level);
|
||||
|
||||
mpc55xx_edma_disable_hardware_requests(edma_tcd);
|
||||
mpc55xx_edma_disable_error_interrupts(edma_tcd);
|
||||
}
|
||||
|
||||
rtems_status_code mpc55xx_edma_obtain_channel(
|
||||
edma_channel_context *ctx,
|
||||
unsigned irq_priority
|
||||
)
|
||||
{
|
||||
rtems_status_code sc = mpc55xx_edma_obtain_channel_by_tcd(ctx->edma_tcd);
|
||||
if (sc == RTEMS_SUCCESSFUL) {
|
||||
unsigned channel_index = edma_channel_index_of_tcd(ctx->edma_tcd);
|
||||
|
||||
sc = mpc55xx_interrupt_handler_install(
|
||||
MPC55XX_IRQ_EDMA(channel_index),
|
||||
"eDMA Channel",
|
||||
RTEMS_INTERRUPT_SHARED,
|
||||
irq_priority,
|
||||
edma_interrupt_handler,
|
||||
ctx
|
||||
);
|
||||
if (sc == RTEMS_SUCCESSFUL) {
|
||||
rtems_chain_prepend(&edma_channel_chain, &ctx->node);
|
||||
mpc55xx_edma_enable_error_interrupts(ctx->edma_tcd);
|
||||
} else {
|
||||
mpc55xx_edma_release_channel_by_tcd(ctx->edma_tcd);
|
||||
sc = RTEMS_IO_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return sc;
|
||||
}
|
||||
|
||||
void mpc55xx_edma_release_channel(edma_channel_context *ctx)
|
||||
{
|
||||
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
||||
unsigned channel_index = edma_channel_index_of_tcd(ctx->edma_tcd);
|
||||
|
||||
mpc55xx_edma_release_channel_by_tcd(ctx->edma_tcd);
|
||||
rtems_chain_extract(&ctx->node);
|
||||
|
||||
sc = rtems_interrupt_handler_remove(
|
||||
MPC55XX_IRQ_EDMA(channel_index),
|
||||
edma_interrupt_handler,
|
||||
ctx
|
||||
);
|
||||
if (sc != RTEMS_SUCCESSFUL) {
|
||||
bsp_fatal(MPC55XX_FATAL_EDMA_IRQ_REMOVE);
|
||||
}
|
||||
}
|
||||
|
||||
void mpc55xx_edma_copy(
|
||||
volatile struct tcd_t *edma_tcd,
|
||||
const struct tcd_t *source_tcd
|
||||
)
|
||||
{
|
||||
/* Clear DONE flag */
|
||||
edma_tcd->BMF.R = 0;
|
||||
|
||||
edma_tcd->SADDR = source_tcd->SADDR;
|
||||
edma_tcd->SDF.R = source_tcd->SDF.R;
|
||||
edma_tcd->NBYTES = source_tcd->NBYTES;
|
||||
edma_tcd->SLAST = source_tcd->SLAST;
|
||||
edma_tcd->DADDR = source_tcd->DADDR;
|
||||
edma_tcd->CDF.R = source_tcd->CDF.R;
|
||||
edma_tcd->DLAST_SGA = source_tcd->DLAST_SGA;
|
||||
edma_tcd->BMF.R = source_tcd->BMF.R;
|
||||
}
|
||||
|
||||
void mpc55xx_edma_copy_and_enable_hardware_requests(
|
||||
volatile struct tcd_t *edma_tcd,
|
||||
const struct tcd_t *source_tcd
|
||||
)
|
||||
{
|
||||
mpc55xx_edma_copy(edma_tcd, source_tcd);
|
||||
mpc55xx_edma_enable_hardware_requests(edma_tcd);
|
||||
}
|
||||
|
||||
void mpc55xx_edma_sg_link(
|
||||
volatile struct tcd_t *edma_tcd,
|
||||
const struct tcd_t *source_tcd
|
||||
)
|
||||
{
|
||||
edma_tcd->DLAST_SGA = (int32_t) source_tcd;
|
||||
edma_tcd->BMF.B.E_SG = 1;
|
||||
|
||||
if (!edma_tcd->BMF.B.E_SG) {
|
||||
mpc55xx_edma_copy(edma_tcd, source_tcd);
|
||||
}
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @ingroup mpc55xx
|
||||
*
|
||||
* @brief Enhanced Modular Input Output Subsystem (eMIOS).
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009-2011 embedded brains GmbH. All rights reserved.
|
||||
*
|
||||
* embedded brains GmbH
|
||||
* Obere Lagerstr. 30
|
||||
* 82178 Puchheim
|
||||
* Germany
|
||||
* <rtems@embedded-brains.de>
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
*/
|
||||
|
||||
#include <mpc55xx/emios.h>
|
||||
|
||||
#ifdef MPC55XX_HAS_EMIOS
|
||||
|
||||
/**
|
||||
* @brief Initialize the eMIOS module.
|
||||
*
|
||||
* The module is enabled. It is configured to use the internal clock. The
|
||||
* global prescaler value is set to @a prescaler. If the value is greater than
|
||||
* the maximum the maxium value will be used instead. A prescaler value of
|
||||
* zero disables the clock.
|
||||
*
|
||||
* @note No protection against concurrent execution.
|
||||
*/
|
||||
void mpc55xx_emios_initialize( unsigned prescaler)
|
||||
{
|
||||
union EMIOS_MCR_tag mcr = MPC55XX_ZERO_FLAGS;
|
||||
|
||||
/* Enable module */
|
||||
mcr.B.MDIS = 0;
|
||||
|
||||
/* Disable debug mode */
|
||||
mcr.B.FRZ = 1;
|
||||
|
||||
/* Enable global time base */
|
||||
mcr.B.GTBE = 1;
|
||||
|
||||
/* Disable global prescaler (= disable clock) */
|
||||
mcr.B.GPREN = 0;
|
||||
|
||||
/* Set MCR */
|
||||
EMIOS.MCR.R = mcr.R;
|
||||
|
||||
/* Set OUDR */
|
||||
EMIOS.OUDR.R = 0;
|
||||
|
||||
/* Set global prescaler value */
|
||||
mpc55xx_emios_set_global_prescaler( prescaler);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the global prescaler value of the eMIOS module.
|
||||
*/
|
||||
unsigned mpc55xx_emios_global_prescaler( void)
|
||||
{
|
||||
union EMIOS_MCR_tag mcr = EMIOS.MCR;
|
||||
|
||||
if (mcr.B.GPREN != 0) {
|
||||
return mcr.B.GPRE + 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the global prescaler value of the eMIOS module.
|
||||
*
|
||||
* The global prescaler value is set to @a prescaler. If the value is greater
|
||||
* than the maximum the maxium value will be used instead. A prescaler value
|
||||
* of zero disables the clock.
|
||||
*
|
||||
* @note No protection against concurrent execution.
|
||||
*/
|
||||
void mpc55xx_emios_set_global_prescaler( unsigned prescaler)
|
||||
{
|
||||
union EMIOS_MCR_tag mcr = EMIOS.MCR;
|
||||
|
||||
/* Enable or disable the global prescaler */
|
||||
mcr.B.GPREN = prescaler > 0 ? 1 : 0;
|
||||
|
||||
/* Set global prescaler value */
|
||||
if (prescaler > 256) {
|
||||
prescaler = 256;
|
||||
} else if (prescaler < 1) {
|
||||
prescaler = 1;
|
||||
}
|
||||
mcr.B.GPRE = prescaler - 1;
|
||||
|
||||
/* Set MCR */
|
||||
EMIOS.MCR.R = mcr.R;
|
||||
}
|
||||
|
||||
#endif /* MPC55XX_HAS_EMIOS */
|
||||
@@ -1,20 +0,0 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @ingroup mpc55xx
|
||||
*
|
||||
* @brief Empty file.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008
|
||||
* Embedded Brains GmbH
|
||||
* Obere Lagerstr. 30
|
||||
* D-82178 Puchheim
|
||||
* Germany
|
||||
* rtems@embedded-brains.de
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
*/
|
||||
@@ -1,165 +0,0 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @ingroup mpc55xx
|
||||
*
|
||||
* @brief Source file for MPC55XX interrupt support.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008-2012 embedded brains GmbH. All rights reserved.
|
||||
*
|
||||
* embedded brains GmbH
|
||||
* Obere Lagerstr. 30
|
||||
* 82178 Puchheim
|
||||
* Germany
|
||||
* <rtems@embedded-brains.de>
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
*/
|
||||
|
||||
#include <mpc55xx/regs.h>
|
||||
|
||||
#include <libcpu/powerpc-utility.h>
|
||||
|
||||
#include <bsp/irq.h>
|
||||
#include <bsp/vectors.h>
|
||||
#include <bsp/irq-generic.h>
|
||||
|
||||
#define RTEMS_STATUS_CHECKS_USE_PRINTK
|
||||
|
||||
#include <rtems/status-checks.h>
|
||||
|
||||
/**
|
||||
* @brief Returns the priority @a priority of IRQ @a vector from the INTC.
|
||||
*/
|
||||
rtems_status_code mpc55xx_intc_get_priority( rtems_vector_number vector, unsigned *priority)
|
||||
{
|
||||
if (MPC55XX_IRQ_IS_VALID( vector)) {
|
||||
*priority = INTC.PSR [vector].B.PRI;
|
||||
return RTEMS_SUCCESSFUL;
|
||||
} else {
|
||||
*priority = MPC55XX_INTC_INVALID_PRIORITY;
|
||||
return RTEMS_INVALID_NUMBER;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the priority of IRQ @a vector to @a priority at the INTC.
|
||||
*/
|
||||
rtems_status_code mpc55xx_intc_set_priority( rtems_vector_number vector, unsigned priority)
|
||||
{
|
||||
if (MPC55XX_IRQ_IS_VALID( vector) && MPC55XX_INTC_IS_VALID_PRIORITY( priority)) {
|
||||
INTC.PSR [vector].B.PRI = priority;
|
||||
if (INTC.PSR [vector].B.PRI == priority) {
|
||||
return RTEMS_SUCCESSFUL;
|
||||
} else {
|
||||
return RTEMS_IO_ERROR;
|
||||
}
|
||||
} else {
|
||||
return RTEMS_INVALID_NUMBER;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Raises the software IRQ with number @a vector.
|
||||
*/
|
||||
rtems_status_code mpc55xx_intc_raise_software_irq( rtems_vector_number vector)
|
||||
{
|
||||
if (MPC55XX_IRQ_IS_SOFTWARE( vector)) {
|
||||
INTC.SSCIR [vector].B.SET = 1;
|
||||
return RTEMS_SUCCESSFUL;
|
||||
} else {
|
||||
return RTEMS_INVALID_NUMBER;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clears the software IRQ with number @a vector.
|
||||
*/
|
||||
rtems_status_code mpc55xx_intc_clear_software_irq( rtems_vector_number vector)
|
||||
{
|
||||
if (MPC55XX_IRQ_IS_SOFTWARE( vector)) {
|
||||
INTC.SSCIR [vector].B.CLR = 1;
|
||||
return RTEMS_SUCCESSFUL;
|
||||
} else {
|
||||
return RTEMS_INVALID_NUMBER;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Installs interrupt handler and sets priority.
|
||||
*/
|
||||
rtems_status_code mpc55xx_interrupt_handler_install(
|
||||
rtems_vector_number vector,
|
||||
const char *info,
|
||||
rtems_option options,
|
||||
unsigned priority,
|
||||
rtems_interrupt_handler handler,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
if (MPC55XX_IRQ_IS_VALID( vector) && MPC55XX_INTC_IS_VALID_PRIORITY( priority)) {
|
||||
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
||||
|
||||
sc = rtems_interrupt_handler_install( vector, info, options, handler, arg);
|
||||
RTEMS_CHECK_SC( sc, "Install interrupt handler");
|
||||
|
||||
return mpc55xx_intc_set_priority( vector, priority);
|
||||
} else {
|
||||
return RTEMS_INVALID_NUMBER;
|
||||
}
|
||||
}
|
||||
|
||||
void bsp_interrupt_dispatch(uintptr_t exception_number)
|
||||
{
|
||||
/* Acknowledge interrupt request */
|
||||
rtems_vector_number vector = INTC.IACKR.B.INTVEC;
|
||||
|
||||
/* Save machine state and enable external exceptions */
|
||||
uint32_t msr = ppc_external_exceptions_enable();
|
||||
|
||||
/* Dispatch interrupt handlers */
|
||||
bsp_interrupt_handler_dispatch( vector);
|
||||
|
||||
/* Restore machine state */
|
||||
ppc_external_exceptions_disable( msr);
|
||||
|
||||
/* End of interrupt */
|
||||
INTC.EOIR.R = 1;
|
||||
}
|
||||
|
||||
rtems_status_code bsp_interrupt_facility_initialize(void)
|
||||
{
|
||||
rtems_vector_number vector;
|
||||
|
||||
/* Initialize interrupt controller */
|
||||
|
||||
/* Disable all interrupts */
|
||||
for (vector = MPC55XX_IRQ_MIN; vector <= MPC55XX_IRQ_MAX; ++vector) {
|
||||
INTC.PSR [vector].B.PRI = MPC55XX_INTC_DISABLED_PRIORITY;
|
||||
}
|
||||
|
||||
/* Software vector mode */
|
||||
INTC.MCR.B.VTES = 0;
|
||||
INTC.MCR.B.HVEN = 0;
|
||||
|
||||
/* Set current priority to 0 */
|
||||
INTC.CPR.B.PRI = 0;
|
||||
|
||||
return RTEMS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
void bsp_interrupt_vector_enable( rtems_vector_number vector)
|
||||
{
|
||||
bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
|
||||
mpc55xx_intc_set_priority( vector, MPC55XX_INTC_DEFAULT_PRIORITY);
|
||||
}
|
||||
|
||||
void bsp_interrupt_vector_disable( rtems_vector_number vector)
|
||||
{
|
||||
bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
|
||||
mpc55xx_intc_set_priority( vector, MPC55XX_INTC_DISABLED_PRIORITY);
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @ingroup mpc55xx_asm
|
||||
*
|
||||
* @brief Memory copy functions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008
|
||||
* Embedded Brains GmbH
|
||||
* Obere Lagerstr. 30
|
||||
* D-82178 Puchheim
|
||||
* Germany
|
||||
* rtems@embedded-brains.de
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
*/
|
||||
|
||||
#include <libcpu/powerpc-utility.h>
|
||||
#include <bspopts.h>
|
||||
|
||||
.section ".bsp_start_text", "ax"
|
||||
|
||||
/**
|
||||
* @fn int mpc55xx_copy_8( const void *src, void *dest, size_t n)
|
||||
*
|
||||
* @brief Copy @a n bytes from @a src to @a dest with 8 byte reads and writes.
|
||||
*
|
||||
* The memory areas should not overlap. The addresses @a src and @a dest have
|
||||
* to be aligned on 8 byte boundaries. The size @a n must be evenly divisible by 8.
|
||||
* The SPE operations @b evxor, @b evlddx and @b evstddx will be used.
|
||||
*/
|
||||
#if ((MPC55XX_CHIP_TYPE>=5510) && (MPC55XX_CHIP_TYPE<=5517))
|
||||
GLOBAL_FUNCTION mpc55xx_copy_8
|
||||
#endif /* ((MPC55XX_CHIP_TYPE>=5510) && (MPC55XX_CHIP_TYPE<=5517)) */
|
||||
GLOBAL_FUNCTION mpc55xx_copy_4
|
||||
/* Loop counter = data size / 4 */
|
||||
srwi. r5, r5, 2
|
||||
beqlr
|
||||
mtctr r5
|
||||
xor r5,r5,r5
|
||||
copy_data4:
|
||||
lwzx r6, r5, r3
|
||||
stwx r6, r5, r4
|
||||
addi r5, r5, 4
|
||||
bdnz copy_data4
|
||||
|
||||
/* Return */
|
||||
blr
|
||||
|
||||
#if !((MPC55XX_CHIP_TYPE>=5510) && (MPC55XX_CHIP_TYPE<=5517))
|
||||
/**
|
||||
* @fn int mpc55xx_copy_8( const void *src, void *dest, size_t n)
|
||||
*
|
||||
* @brief Copy @a n bytes from @a src to @a dest with 8 byte reads and writes.
|
||||
*
|
||||
* The memory areas should not overlap. The addresses @a src and @a dest have
|
||||
* to be aligned on 8 byte boundaries. The size @a n must be evenly divisible by 8.
|
||||
* The SPE operations @b evxor, @b evlddx and @b evstddx will be used.
|
||||
*/
|
||||
GLOBAL_FUNCTION mpc55xx_copy_8
|
||||
/* Loop counter = data size / 8 */
|
||||
srwi. r5, r5, 3
|
||||
beqlr
|
||||
mtctr r5
|
||||
|
||||
/* Set offset */
|
||||
evxor r5, r5, r5
|
||||
|
||||
copy_data:
|
||||
evlddx r6, r3, r5
|
||||
evstddx r6, r4, r5
|
||||
addi r5, r5, 8
|
||||
bdnz copy_data
|
||||
|
||||
/* Return */
|
||||
blr
|
||||
#endif /*!((MPC55XX_CHIP_TYPE>=5510) && (MPC55XX_CHIP_TYPE<=5517))*/
|
||||
@@ -1,698 +0,0 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @ingroup mpc55xx
|
||||
*
|
||||
* @brief MPC55XX flash memory support.
|
||||
*
|
||||
* I set my MMU up to map what will finally be in flash into RAM and at the
|
||||
* same time I map the flash to a different location. When the software
|
||||
* is tested I can use this to copy the RAM version of the program into
|
||||
* the flash and when I reboot I'm running out of flash.
|
||||
*
|
||||
* I use a flag word located after the boot configuration half-word to
|
||||
* indicate that the MMU should be left alone, and I don't include the RCHW
|
||||
* or that flag in my call to this routine.
|
||||
*
|
||||
* There are obviously other uses for this.
|
||||
**/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009-2011
|
||||
* HD Associates, Inc.
|
||||
* 18 Main Street
|
||||
* Pepperell, MA 01463
|
||||
* USA
|
||||
* dufault@hda.com
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <mpc55xx/regs.h>
|
||||
#include <mpc55xx/mpc55xx.h>
|
||||
|
||||
#include <libcpu/powerpc-utility.h>
|
||||
#include <rtems/powerpc/registers.h>
|
||||
|
||||
#if MPC55XX_CHIP_FAMILY == 555 || MPC55XX_CHIP_FAMILY == 556
|
||||
|
||||
/* Set up the memory ranges for the flash on
|
||||
* the MPC5553, MPC5554, MPC5566 and MPC5567.
|
||||
* I check if it is an unknown CPU and return an error.
|
||||
*
|
||||
* These CPUS have a low, mid, and high space of memory.
|
||||
*
|
||||
* Only the low space really needs a table like this, but for simplicity
|
||||
* I do low, mid, and high the same way.
|
||||
*/
|
||||
struct range { /* A memory range. */
|
||||
uint32_t lower;
|
||||
uint32_t upper;
|
||||
};
|
||||
|
||||
/* The ranges of the memory banks for the low space. All the
|
||||
* chips I'm looking at share this low format, identified by LAS=6:
|
||||
* 2 16K banks,
|
||||
* 2 48K banks,
|
||||
* 2 64K banks.
|
||||
*/
|
||||
static const struct range lsel_ranges[] = {
|
||||
{ 0, (1*16 )*1024 - 1},
|
||||
{(1*16 )*1024, (2*16 )*1024 - 1},
|
||||
{(2*16 )*1024, (2*16 + 1*48 )*1024 - 1},
|
||||
{(2*16 + 1*48 )*1024, (2*16 + 2*48 )*1024 - 1},
|
||||
{(2*16 + 2*48 )*1024, (2*16 + 2*48 + 1*64)*1024 - 1},
|
||||
{(2*16 + 2*48 + 1*64)*1024, (2*16 + 2*48 + 2*64)*1024 - 1},
|
||||
};
|
||||
|
||||
/* The ranges of the memory blocks for the mid banks, 2 128K banks.
|
||||
* Again, all the chips share this, identified by MAS=0.
|
||||
*/
|
||||
#define MBSTART ((2*16+2*48+2*64)*1024)
|
||||
static const struct range msel_ranges[] = {
|
||||
{MBSTART , MBSTART + 1*128*1024 - 1},
|
||||
{MBSTART + 1*128*1024, MBSTART + 2*128*1024 - 1},
|
||||
};
|
||||
|
||||
/* The ranges of the memory blocks for the high banks.
|
||||
* There are N 128K banks, where N <= 20,
|
||||
* and is identified by looking at the SIZE field.
|
||||
*
|
||||
* This could benefit from being redone to save a few bytes
|
||||
* and provide for bigger flash spaces.
|
||||
*/
|
||||
#define HBSTART (MBSTART+2*128*1024)
|
||||
static const struct range hbsel_ranges[] = {
|
||||
{HBSTART , HBSTART + 1*128*1024 - 1},
|
||||
{HBSTART + 1*128*1024, HBSTART + 2*128*1024 - 1},
|
||||
{HBSTART + 2*128*1024, HBSTART + 3*128*1024 - 1},
|
||||
{HBSTART + 3*128*1024, HBSTART + 4*128*1024 - 1},
|
||||
{HBSTART + 4*128*1024, HBSTART + 5*128*1024 - 1},
|
||||
{HBSTART + 5*128*1024, HBSTART + 6*128*1024 - 1},
|
||||
{HBSTART + 6*128*1024, HBSTART + 7*128*1024 - 1},
|
||||
{HBSTART + 7*128*1024, HBSTART + 8*128*1024 - 1},
|
||||
{HBSTART + 8*128*1024, HBSTART + 9*128*1024 - 1},
|
||||
{HBSTART + 9*128*1024, HBSTART + 10*128*1024 - 1},
|
||||
{HBSTART + 10*128*1024, HBSTART + 11*128*1024 - 1},
|
||||
{HBSTART + 11*128*1024, HBSTART + 12*128*1024 - 1},
|
||||
{HBSTART + 12*128*1024, HBSTART + 13*128*1024 - 1},
|
||||
{HBSTART + 13*128*1024, HBSTART + 14*128*1024 - 1},
|
||||
{HBSTART + 14*128*1024, HBSTART + 15*128*1024 - 1},
|
||||
{HBSTART + 15*128*1024, HBSTART + 16*128*1024 - 1},
|
||||
{HBSTART + 16*128*1024, HBSTART + 17*128*1024 - 1},
|
||||
{HBSTART + 17*128*1024, HBSTART + 18*128*1024 - 1},
|
||||
{HBSTART + 18*128*1024, HBSTART + 19*128*1024 - 1},
|
||||
{HBSTART + 19*128*1024, HBSTART + 20*128*1024 - 1},
|
||||
};
|
||||
|
||||
/* Set bits in a bitmask to indicate which banks are
|
||||
* within the range "first" and "last".
|
||||
*/
|
||||
static void
|
||||
range_set(
|
||||
uint32_t first,
|
||||
uint32_t last,
|
||||
int *p_bits,
|
||||
const struct range *pr,
|
||||
int n_range
|
||||
)
|
||||
{
|
||||
int i;
|
||||
int bits = 0;
|
||||
for (i = 0; i < n_range; i++) {
|
||||
/* If the upper limit is less than "first" or the lower limit
|
||||
* is greater than "last" then the block is not in range.
|
||||
*/
|
||||
if ( !(pr[i].upper < first || pr[i].lower > last)) {
|
||||
bits |= (1 << i); /* This block is in the range, set the bit. */
|
||||
}
|
||||
|
||||
}
|
||||
*p_bits = bits;
|
||||
}
|
||||
|
||||
/** Return the size of the on-chip flash
|
||||
* verifying that this is a device that we know about.
|
||||
* @return 0 for OK, non-zero for error:
|
||||
* - MPC55XX_FLASH_VERIFY_ERR for LAS not 6 or MAS not 0.
|
||||
* @note This is overriding what verify means!
|
||||
* - MPC55XX_FLASH_SIZE_ERR Not a chip I've checked against the manual,
|
||||
* athat is, SIZE not 5, 7, or 11.
|
||||
*/
|
||||
int
|
||||
mpc55xx_flash_size(
|
||||
uint32_t *p_size /**< The size is returned here. */
|
||||
)
|
||||
{
|
||||
/* On the MPC5553, MPC5554, MPC5566, and MP5567 the
|
||||
* low address space LAS field is 0x6 and all have
|
||||
* six blocks sized 2*16k, 2*48k, and 2*64k.
|
||||
*
|
||||
* All the mid and high address spaces have 128K blocks.
|
||||
*
|
||||
* The mid address space MAS size field is 0 for the above machines,
|
||||
* and they all have 2 128K blocks.
|
||||
*
|
||||
* For the high address space we look at the
|
||||
* size field to figure out the size. The SIZE field is:
|
||||
*
|
||||
* 5 for 1.5MB (MPC5553)
|
||||
* 7 for 2MB (MPC5554, MPC5567)
|
||||
* 11 for 3MB (MPC5566)
|
||||
*/
|
||||
int hblocks; /* The number of blocks in the high address space. */
|
||||
|
||||
/* Verify the configuration matches one of the chips that I've checked out.
|
||||
*/
|
||||
if (FLASH.MCR.B.LAS != 6 || FLASH.MCR.B.MAS != 0) {
|
||||
return MPC55XX_FLASH_VERIFY_ERR;
|
||||
}
|
||||
|
||||
switch(FLASH.MCR.B.SIZE) {
|
||||
case 5:
|
||||
hblocks = 8;
|
||||
break;
|
||||
|
||||
case 7:
|
||||
hblocks = 12;
|
||||
break;
|
||||
|
||||
case 11:
|
||||
hblocks = 20;
|
||||
break;
|
||||
|
||||
default:
|
||||
return MPC55XX_FLASH_SIZE_ERR;
|
||||
}
|
||||
|
||||
/* The first two banks are 256K.
|
||||
* The high block has "hblocks" 128K blocks.
|
||||
*/
|
||||
*p_size = 256*1024 + 256*1024 + hblocks * 128*1024;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Unlock the flash blocks if "p_locked" points to something that is 0.
|
||||
* If it is a NULL pointer then we aren't allowed to do the unlock.
|
||||
*/
|
||||
static int
|
||||
unlock_once(int lsel, int msel, int hbsel, int *p_locked)
|
||||
{
|
||||
union LMLR_tag lmlr;
|
||||
union SLMLR_tag slmlr;
|
||||
union HLR_tag hlr;
|
||||
|
||||
/* If we're already locked return.
|
||||
*/
|
||||
if (p_locked && (*p_locked == 1)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Do we have to lock something in the low or mid block?
|
||||
*/
|
||||
lmlr = FLASH.LMLR;
|
||||
if ((lsel || msel) && (lmlr.B.LME == 0)) {
|
||||
union LMLR_tag lmlr_unlock;
|
||||
lmlr_unlock.B.LLOCK=~lsel;
|
||||
lmlr_unlock.B.MLOCK=~msel;
|
||||
lmlr_unlock.B.SLOCK=1;
|
||||
|
||||
if (lmlr.B.LLOCK != lmlr_unlock.B.LLOCK ||
|
||||
lmlr.B.MLOCK != lmlr_unlock.B.MLOCK) {
|
||||
if (p_locked == 0) {
|
||||
return MPC55XX_FLASH_LOCK_ERR;
|
||||
} else {
|
||||
*p_locked = 1;
|
||||
}
|
||||
FLASH.LMLR.R = 0xA1A11111; /* Unlock. */
|
||||
FLASH.LMLR = lmlr_unlock;
|
||||
}
|
||||
}
|
||||
|
||||
slmlr = FLASH.SLMLR;
|
||||
if ((lsel || msel) && (slmlr.B.SLE == 0)) {
|
||||
union SLMLR_tag slmlr_unlock;
|
||||
slmlr_unlock.B.SLLOCK=~lsel;
|
||||
slmlr_unlock.B.SMLOCK=~msel;
|
||||
slmlr_unlock.B.SSLOCK=1;
|
||||
|
||||
if (slmlr.B.SLLOCK != slmlr_unlock.B.SLLOCK ||
|
||||
slmlr.B.SMLOCK != slmlr_unlock.B.SMLOCK) {
|
||||
if (p_locked == 0) {
|
||||
return MPC55XX_FLASH_LOCK_ERR;
|
||||
} else {
|
||||
*p_locked = 1;
|
||||
}
|
||||
FLASH.SLMLR.R = 0xC3C33333; /* Unlock. */
|
||||
FLASH.SLMLR = slmlr_unlock;
|
||||
}
|
||||
}
|
||||
|
||||
/* Do we have to unlock something in the high block?
|
||||
*/
|
||||
hlr = FLASH.HLR;
|
||||
if (hbsel && (hlr.B.HBE == 0)) {
|
||||
union HLR_tag hlr_unlock;
|
||||
hlr_unlock.B.HBLOCK = ~hbsel;
|
||||
|
||||
if (hlr.B.HBLOCK != hlr_unlock.B.HBLOCK) {
|
||||
if (p_locked == 0) {
|
||||
return MPC55XX_FLASH_LOCK_ERR;
|
||||
} else {
|
||||
*p_locked = 1;
|
||||
}
|
||||
FLASH.HLR.R = 0xB2B22222; /* Unlock. */
|
||||
FLASH.HLR = hlr_unlock;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
tsize(int i)
|
||||
{
|
||||
return 1 << (10 + 2 * i);
|
||||
}
|
||||
|
||||
static int
|
||||
addr_map(
|
||||
int to_phys, /* If 1 lookup physical else lookup mapped. */
|
||||
const void *addr, /* The address to look up. */
|
||||
uint32_t *p_result /* Result is here. */
|
||||
)
|
||||
{
|
||||
uint32_t u_addr = (uint32_t)addr;
|
||||
uint32_t mas0, mas1, mas2, mas3;
|
||||
uint32_t start, end;
|
||||
rtems_interrupt_level level;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
mas0 = 0x10000000 | (i << 16);
|
||||
rtems_interrupt_disable(level);
|
||||
PPC_SET_SPECIAL_PURPOSE_REGISTER(FSL_EIS_MAS0, mas0);
|
||||
asm volatile("tlbre");
|
||||
mas1 = PPC_SPECIAL_PURPOSE_REGISTER(FSL_EIS_MAS1);
|
||||
mas2 = PPC_SPECIAL_PURPOSE_REGISTER(FSL_EIS_MAS2);
|
||||
mas3 = PPC_SPECIAL_PURPOSE_REGISTER(FSL_EIS_MAS3);
|
||||
rtems_interrupt_enable(level);
|
||||
|
||||
if (mas1 & 0x80000000) {
|
||||
/* Valid. */
|
||||
start = (to_phys ? mas2 : mas3) & 0xFFFFF000;
|
||||
end = start + tsize((mas1 >> 8) & 0x0000000F);
|
||||
/* Are we within range?
|
||||
*/
|
||||
if (start <= u_addr && end >= u_addr) {
|
||||
uint32_t offset = (to_phys ? mas3 : mas2) & 0xFFFFF000;
|
||||
*p_result = u_addr - offset;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Not found in a TLB.
|
||||
*/
|
||||
return ESRCH;
|
||||
}
|
||||
|
||||
/** Return the physical address corresponding to a mapped address.
|
||||
@return 0 if OK, ESRCH if not found in TLB1.
|
||||
**/
|
||||
int
|
||||
mpc55xx_physical_address(
|
||||
const void *addr, /**< Mapped address. */
|
||||
uint32_t *p_result /**< Result returned here. */
|
||||
)
|
||||
{
|
||||
return addr_map(1, addr, p_result);
|
||||
}
|
||||
|
||||
/** Return the mapped address corresponding to a mapped address.
|
||||
@return 0 if OK, ESRCH if not found in TLB1.
|
||||
**/
|
||||
int
|
||||
mpc55xx_mapped_address(
|
||||
const void *addr, /**< Mapped address. */
|
||||
uint32_t *p_result /**< Result returned here. */
|
||||
)
|
||||
{
|
||||
return addr_map(0, addr, p_result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy memory from an address into the flash when flash is relocated
|
||||
* If programming fails the address that it failed at can be returned.
|
||||
@note At end of operation the flash may be left writable.
|
||||
* Use mpc55xx_flash_read_only() to set read-only.
|
||||
@return Zero for OK, non-zero for error:
|
||||
* - ESRCH Can't lookup where something lives.
|
||||
* - EPERM Attempt to write to non-writable flash.
|
||||
* - ETXTBSY Attempt to flash overlapping regions.
|
||||
* - MPC55XX_FLASH_CONFIG_ERR for LAS not 6 or MAS not 0.
|
||||
* - MPC55XX_FLASH_SIZE_ERR for SIZE not 5, 7, or 11.
|
||||
* - MPC55XX_FLASH_RANGE_ERR for illegal access:
|
||||
* - first or first+last outside of flash;
|
||||
* - first not on a mod(8) boundary;
|
||||
* - nbytes not multiple of 8.
|
||||
* - MPC55XX_FLASH_ERASE_ERR Erase requested but failed.
|
||||
* - MPC55XX_FLASH_PROGRAM_ERR Program requested but failed.
|
||||
* - MPC55XX_FLASH_NOT_BLANK_ERR Blank check requested but not blank.
|
||||
* - MPC55XX_FLASH_VERIFY_ERR Verify requested but failed.
|
||||
* - MPC55XX_FLASH_LOCK_ERR Unlock requested but failed.
|
||||
**/
|
||||
|
||||
int
|
||||
mpc55xx_flash_copy_op(
|
||||
void *dest, /**< An address in the flash to copy to. */
|
||||
const void *src, /**< An address in memory to copy from. */
|
||||
size_t nbytes, /**< The number of bytes to copy. */
|
||||
uint32_t opmask, /**< Bitmask of operations to perform.
|
||||
* - MPC55XX_FLASH_UNLOCK: Unlock the blocks.
|
||||
* - MPC55XX_FLASH_ERASE: Erase the blocks.
|
||||
* - MPC55XX_FLASH_BLANK_CHECK: Verify the blocks are blank.
|
||||
* - MPC55XX_FLASH_PROGRAM: Program the FLASH.
|
||||
* - MPC55XX_FLASH_VERIFY: Verify the regions match.
|
||||
**/
|
||||
uint32_t *p_fail /**< If not NULL then the address where the operation
|
||||
* failed is returned here.
|
||||
**/
|
||||
)
|
||||
{
|
||||
uint32_t udest, usrc, flash_size;
|
||||
int r;
|
||||
int peg; /* Program or Erase Good - Did it work? */
|
||||
|
||||
int lsel; /* Low block select bits. */
|
||||
int msel; /* Mid block select bits. */
|
||||
int hbsel; /* High block select bits. */
|
||||
|
||||
int s_lsel; /* Source Low block select bits. */
|
||||
int s_msel; /* Source Mid block select bits. */
|
||||
int s_hbsel; /* Source High block select bits. */
|
||||
|
||||
int unlocked = 0;
|
||||
int *p_unlocked;
|
||||
int i;
|
||||
int nwords; /* The number of 32 bit words to write. */
|
||||
volatile uint32_t *flash; /* Where the flash is mapped in. */
|
||||
volatile uint32_t *memory; /* What to copy into flash. */
|
||||
const void *flashing_from; /* Where we are flahsing from.
|
||||
* "const" is to match invalidate cache function signature. */
|
||||
uint32_t offset; /* Where the FLASH is mapped into memory. */
|
||||
|
||||
if ( (r = mpc55xx_flash_size(&flash_size))) {
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Get where the flash is mapped in.
|
||||
*/
|
||||
offset = mpc55xx_flash_address();
|
||||
|
||||
udest = ((uint32_t)dest) - offset;
|
||||
if ( (r = mpc55xx_physical_address(src, &usrc)) ) {
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Verify that the address being programmed is in flash and that it is
|
||||
* a multiple of 64 bits.
|
||||
* Someone else can remove the 64-bit restriction.
|
||||
*/
|
||||
if (udest > flash_size ||
|
||||
udest + nbytes > flash_size ||
|
||||
(udest & 0x7) != 0 ||
|
||||
(nbytes & 0x7) != 0) {
|
||||
return MPC55XX_FLASH_RANGE_ERR;
|
||||
}
|
||||
|
||||
if (opmask == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If we're going to do a write-style operation the flash must be writable.
|
||||
*/
|
||||
if ((opmask &
|
||||
(MPC55XX_FLASH_UNLOCK | MPC55XX_FLASH_ERASE | MPC55XX_FLASH_PROGRAM)) &&
|
||||
!mpc55xx_flash_writable()
|
||||
) {
|
||||
return EPERM;
|
||||
}
|
||||
|
||||
/* If we aren't allowed to unlock then set the pointer to zero.
|
||||
* That is how "unlock_once" decides we can't unlock.
|
||||
*/
|
||||
p_unlocked = (opmask & MPC55XX_FLASH_UNLOCK) ? &unlocked : 0;
|
||||
|
||||
/* Set up the bit masks for the blocks to program or erase.
|
||||
*/
|
||||
range_set(udest, udest + nbytes, &lsel, lsel_ranges, RTEMS_ARRAY_SIZE( lsel_ranges));
|
||||
range_set(udest, udest + nbytes, &msel, msel_ranges, RTEMS_ARRAY_SIZE( msel_ranges));
|
||||
range_set(udest, udest + nbytes, &hbsel, hbsel_ranges, RTEMS_ARRAY_SIZE(hbsel_ranges));
|
||||
|
||||
range_set(usrc, usrc + nbytes, &s_lsel, lsel_ranges, RTEMS_ARRAY_SIZE( lsel_ranges));
|
||||
range_set(usrc, usrc + nbytes, &s_msel, msel_ranges, RTEMS_ARRAY_SIZE( msel_ranges));
|
||||
range_set(usrc, usrc + nbytes, &s_hbsel, hbsel_ranges, RTEMS_ARRAY_SIZE(hbsel_ranges));
|
||||
|
||||
/* Are we attempting overlapping flash?
|
||||
*/
|
||||
if ((lsel & s_lsel) | (msel & s_msel) | (hbsel & s_hbsel)) {
|
||||
return ETXTBSY;
|
||||
}
|
||||
|
||||
nwords = nbytes / 4;
|
||||
flash = (volatile uint32_t *)dest;
|
||||
memory = (volatile uint32_t *)src;
|
||||
|
||||
/* In the following sections any "Step N" notes refer to
|
||||
* the steps in "13.4.2.3 Flash Programming" in the reference manual.
|
||||
*/
|
||||
|
||||
if (opmask & MPC55XX_FLASH_ERASE) { /* Erase. */
|
||||
uint32_t flash_biucr_r;
|
||||
if ( (r = unlock_once(lsel, msel, hbsel, p_unlocked)) ) {
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Per errata "e989: FLASH: Disable Prefetch during programming and erase" */
|
||||
flash_biucr_r = FLASH.BIUCR.R;
|
||||
FLASH.BIUCR.B.PFLIM = 0;
|
||||
|
||||
FLASH.MCR.B.ESUS = 0; /* Be sure ESUS is clear. */
|
||||
|
||||
FLASH.MCR.B.ERS = 1; /* Step 1: Select erase. */
|
||||
|
||||
FLASH.LMSR.B.LSEL = lsel; /* Step 2: Select blocks to be erased. */
|
||||
FLASH.LMSR.B.MSEL = msel;
|
||||
FLASH.HSR.B.HBSEL = hbsel;
|
||||
|
||||
flash[0] = 0xffffffff; /* Step 3: Write to any address in the flash
|
||||
* (the "erase interlock write)".
|
||||
*/
|
||||
rtems_cache_flush_multiple_data_lines(
|
||||
RTEMS_DEVOLATILE(void *,flash),
|
||||
sizeof(flash[0])
|
||||
);
|
||||
|
||||
FLASH.MCR.B.EHV = 1; /* Step 4: Enable high V to start erase. */
|
||||
while (FLASH.MCR.B.DONE == 0) { /* Step 5: Wait until done. */
|
||||
}
|
||||
peg = FLASH.MCR.B.PEG; /* Save result. */
|
||||
FLASH.MCR.B.EHV = 0; /* Disable high voltage. */
|
||||
FLASH.MCR.B.ERS = 0; /* De-select erase. */
|
||||
FLASH.BIUCR.R = flash_biucr_r;
|
||||
|
||||
if (peg == 0) {
|
||||
return MPC55XX_FLASH_ERASE_ERR; /* Flash erase failed. */
|
||||
}
|
||||
}
|
||||
|
||||
if (opmask & MPC55XX_FLASH_BLANK_CHECK) { /* Verify blank. */
|
||||
for (i = 0; i < nwords; i++) {
|
||||
if (flash[i] != 0xffffffff) {
|
||||
if (p_fail) {
|
||||
*p_fail = (uint32_t)(flash + i);
|
||||
}
|
||||
return MPC55XX_FLASH_NOT_BLANK_ERR; /* Not blank. */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Program.
|
||||
*/
|
||||
if (opmask & MPC55XX_FLASH_PROGRAM) {
|
||||
int chunk = 0; /* Used to collect programming into 256 bit chunks. */
|
||||
|
||||
if ( (r = unlock_once(lsel, msel, hbsel, p_unlocked)) ) {
|
||||
return r;
|
||||
}
|
||||
FLASH.MCR.B.PGM = 1; /* Step 1 */
|
||||
|
||||
for (flashing_from = (const void *)flash, i = 0; i < nwords; i += 2) {
|
||||
flash[i] = memory[i]; /* Step 2 */
|
||||
flash[i + 1] = memory[i + 1]; /* Always program in min 64 bits. */
|
||||
|
||||
/* Step 3 is "write additional words" */
|
||||
|
||||
/* Try to program in chunks of 256 bits.
|
||||
* Collect the 64 bit writes into 256 bit ones:
|
||||
*/
|
||||
chunk++;
|
||||
if (chunk == 4) {
|
||||
/* Collected 4 64-bits for a 256 bit chunk. */
|
||||
|
||||
rtems_cache_flush_multiple_data_lines(flashing_from, 32); /* Flush cache. */
|
||||
|
||||
FLASH.MCR.B.EHV = 1; /* Step 4: Enable high V. */
|
||||
|
||||
while (FLASH.MCR.B.DONE == 0) { /* Step 5: Wait until done. */
|
||||
}
|
||||
|
||||
peg = FLASH.MCR.B.PEG; /* Step 6: Save result. */
|
||||
FLASH.MCR.B.EHV = 0; /* Step 7: Disable high V. */
|
||||
if (peg == 0) {
|
||||
FLASH.MCR.B.PGM = 0;
|
||||
if (p_fail) {
|
||||
*p_fail = (uint32_t)(flash + i);
|
||||
}
|
||||
return MPC55XX_FLASH_PROGRAM_ERR; /* Programming failed. */
|
||||
}
|
||||
chunk = 0; /* Reset chunk counter. */
|
||||
flashing_from = (const void *)(flash + i);
|
||||
}
|
||||
/* Step 8: Back to step 2. */
|
||||
}
|
||||
|
||||
if (!chunk) {
|
||||
FLASH.MCR.B.PGM = 0;
|
||||
} else {
|
||||
/* If there is anything left in that last chunk flush it out:
|
||||
*/
|
||||
|
||||
rtems_cache_flush_multiple_data_lines(flashing_from, chunk * 8);
|
||||
|
||||
FLASH.MCR.B.EHV = 1;
|
||||
|
||||
while (FLASH.MCR.B.DONE == 0) { /* Wait until done. */
|
||||
}
|
||||
|
||||
peg = FLASH.MCR.B.PEG; /* Save result. */
|
||||
FLASH.MCR.B.EHV = 0; /* Disable high voltage. */
|
||||
FLASH.MCR.B.PGM = 0;
|
||||
|
||||
if (peg == 0) {
|
||||
if (p_fail) {
|
||||
*p_fail = (uint32_t)(flash + i);
|
||||
}
|
||||
return MPC55XX_FLASH_PROGRAM_ERR; /* Programming failed. */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (opmask & MPC55XX_FLASH_VERIFY) { /* Verify memory matches. */
|
||||
for (i = 0; i < nwords; i++) {
|
||||
if (flash[i] != memory[i]) {
|
||||
if (p_fail) { /* Return the failed address. */
|
||||
*p_fail = (uint32_t)(flash + i);
|
||||
}
|
||||
return MPC55XX_FLASH_VERIFY_ERR; /* Verification failed. */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Simple flash copy with a signature that matches memcpy.
|
||||
@note At end of operation the flash may be left writable.
|
||||
* Use mpc55xx_flash_read_only() to set read-only.
|
||||
@return Zero for OK, non-zero for error.
|
||||
* see flash_copy_op() for possible errors.
|
||||
**/
|
||||
int
|
||||
mpc55xx_flash_copy(
|
||||
void *dest, /**< An address in the flash to copy to. */
|
||||
const void *src, /**< An address in the flash copy from. */
|
||||
size_t nbytes /**< The number of bytes to copy. */
|
||||
)
|
||||
{
|
||||
return mpc55xx_flash_copy_op(dest, src, nbytes,
|
||||
(MPC55XX_FLASH_UNLOCK |
|
||||
MPC55XX_FLASH_ERASE |
|
||||
MPC55XX_FLASH_BLANK_CHECK |
|
||||
MPC55XX_FLASH_PROGRAM |
|
||||
MPC55XX_FLASH_VERIFY ), 0);
|
||||
}
|
||||
|
||||
/** Make the flash read-write.
|
||||
@note This assumes the flash is mapped by TLB1 entry 1.
|
||||
*/
|
||||
void
|
||||
mpc55xx_flash_set_read_write(void)
|
||||
{
|
||||
rtems_interrupt_level level;
|
||||
rtems_interrupt_disable(level);
|
||||
PPC_SET_SPECIAL_PURPOSE_REGISTER( FSL_EIS_MAS0, 0x10010000);
|
||||
asm volatile("tlbre");
|
||||
PPC_SET_SPECIAL_PURPOSE_REGISTER_BITS(FSL_EIS_MAS3, 0x0000000C);
|
||||
asm volatile("tlbwe");
|
||||
rtems_interrupt_enable(level);
|
||||
}
|
||||
|
||||
/** Make the flash read-only.
|
||||
@note This assumes the flash is mapped by TLB1 entry 1.
|
||||
*/
|
||||
void
|
||||
mpc55xx_flash_set_read_only(void)
|
||||
{
|
||||
rtems_interrupt_level level;
|
||||
rtems_interrupt_disable(level);
|
||||
PPC_SET_SPECIAL_PURPOSE_REGISTER( FSL_EIS_MAS0, 0x10010000);
|
||||
asm volatile("tlbre");
|
||||
PPC_CLEAR_SPECIAL_PURPOSE_REGISTER_BITS(FSL_EIS_MAS3, 0x0000000C);
|
||||
asm volatile("tlbwe");
|
||||
rtems_interrupt_enable(level);
|
||||
}
|
||||
|
||||
/** See if the flash is writable.
|
||||
* @note This assumes the flash is mapped by TLB1 entry 1.
|
||||
* @note It needs to be writable by both user and supervisor.
|
||||
*/
|
||||
int
|
||||
mpc55xx_flash_writable(void)
|
||||
{
|
||||
uint32_t mas3;
|
||||
rtems_interrupt_level level;
|
||||
|
||||
rtems_interrupt_disable(level);
|
||||
PPC_SET_SPECIAL_PURPOSE_REGISTER( FSL_EIS_MAS0, 0x10010000);
|
||||
asm volatile("tlbre");
|
||||
mas3 = PPC_SPECIAL_PURPOSE_REGISTER(FSL_EIS_MAS3);
|
||||
rtems_interrupt_enable(level);
|
||||
|
||||
return ((mas3 & 0x0000000C) == 0x0000000C) ? 1 : 0;
|
||||
}
|
||||
|
||||
/** Return the address where the flash is mapped in.
|
||||
@note This assumes the flash is mapped by TLB1 entry 1.
|
||||
**/
|
||||
uint32_t
|
||||
mpc55xx_flash_address(void)
|
||||
{
|
||||
uint32_t mas2;
|
||||
rtems_interrupt_level level;
|
||||
|
||||
rtems_interrupt_disable(level);
|
||||
PPC_SET_SPECIAL_PURPOSE_REGISTER( FSL_EIS_MAS0, 0x10010000);
|
||||
asm volatile("tlbre");
|
||||
mas2 = PPC_SPECIAL_PURPOSE_REGISTER(FSL_EIS_MAS2);
|
||||
rtems_interrupt_enable(level);
|
||||
|
||||
return mas2 & 0xFFFFF000;
|
||||
}
|
||||
|
||||
#endif /* MPC55XX_CHIP_FAMILY == 555 || MPC55XX_CHIP_FAMILY == 556 */
|
||||
@@ -1,42 +0,0 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @ingroup mpc55xx
|
||||
*
|
||||
* @brief System Integration Unit Access (SIU).
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2010
|
||||
* Embedded Brains GmbH
|
||||
* Obere Lagerstr. 30
|
||||
* D-82178 Puchheim
|
||||
* Germany
|
||||
* rtems@embedded-brains.de
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
*/
|
||||
|
||||
#include <mpc55xx/regs.h>
|
||||
#include <mpc55xx/mpc55xx.h>
|
||||
#include <mpc55xx/siu.h>
|
||||
|
||||
rtems_status_code mpc55xx_siu_pcr_init(volatile struct SIU_tag *siu,
|
||||
const mpc55xx_siu_pcr_entry_t *pcr_entry)
|
||||
{
|
||||
int idx,cnt;
|
||||
/*
|
||||
* repeat, until end of list reached (pcr_cnt = 0)
|
||||
*/
|
||||
while ((pcr_entry != NULL) &&
|
||||
(pcr_entry->pcr_cnt > 0)) {
|
||||
idx = pcr_entry->pcr_idx;
|
||||
for (cnt = pcr_entry->pcr_cnt;cnt > 0;cnt--) {
|
||||
siu->PCR[idx++].R = pcr_entry->pcr_val.R;
|
||||
}
|
||||
pcr_entry++;
|
||||
}
|
||||
return RTEMS_SUCCESSFUL;
|
||||
}
|
||||
Reference in New Issue
Block a user