From 3694f20d5686e41b6f7b398d793a55f1b4352751 Mon Sep 17 00:00:00 2001 From: Lephe Date: Wed, 21 Oct 2020 18:29:04 +0200 Subject: [PATCH] spu: starter driver, supporting direct CPU access to SPU memory --- include/gint/intc.h | 3 ++ include/gint/mpu/intc.h | 2 +- include/gint/mpu/power.h | 2 +- include/gint/mpu/spu.h | 97 ++++++++++++++++++++++++++++++++++++++++ src/intc/intc.c | 3 ++ src/spu/spu.c | 91 +++++++++++++++++++++++++++++++++++++ 6 files changed, 196 insertions(+), 2 deletions(-) create mode 100644 include/gint/mpu/spu.h create mode 100644 src/spu/spu.c diff --git a/include/gint/intc.h b/include/gint/intc.h index 7a232e2..ff74c07 100644 --- a/include/gint/intc.h +++ b/include/gint/intc.h @@ -38,6 +38,9 @@ enum { INTC_RTC_ATI, INTC_RTC_PRI, INTC_RTC_CUI, + /* SPU; interrupts from the DSPs and the SPU-bound DMA */ + INTC_SPU_DSP0, + INTC_SPU_DSP1, }; //--- diff --git a/include/gint/mpu/intc.h b/include/gint/mpu/intc.h index 95af5ad..d605e95 100644 --- a/include/gint/mpu/intc.h +++ b/include/gint/mpu/intc.h @@ -293,7 +293,7 @@ typedef struct // Forward definitions //--- -/* Provided by core/gint.c */ +/* Provided by intc/intc.c */ extern sh7705_intc_t SH7705_INTC; extern sh7305_intc_t SH7305_INTC; diff --git a/include/gint/mpu/power.h b/include/gint/mpu/power.h index bd757cd..274c297 100644 --- a/include/gint/mpu/power.h +++ b/include/gint/mpu/power.h @@ -82,7 +82,7 @@ typedef volatile struct uint32_t :1; uint32_t I2C :1; uint32_t :1; - uint32_t SPU :1; + uint32_t FSI_SPU :1; uint32_t _unknown2 :1; uint32_t :1; uint32_t LCDC :1; diff --git a/include/gint/mpu/spu.h b/include/gint/mpu/spu.h new file mode 100644 index 0000000..aed6f87 --- /dev/null +++ b/include/gint/mpu/spu.h @@ -0,0 +1,97 @@ +//--- +// gint:mpu:spu - Sound Processing Unit and its DSPs +//--- + +#ifndef GINT_MPU_SPU +#define GINT_MPU_SPU + +#include + +typedef volatile struct +{ + uint32_t PBANKC0; /* Program Bank Control 0 */ + uint32_t PBANKC1; /* Program Bank Control 1 */ + pad(0x8); + + uint32_t XBANKC0; /* X Bank Control 0 */ + uint32_t XBANKC1; /* X Bank Control 1 */ + pad(0x10); + + lword_union(SPUSRST, /* SPU Software Reset */ + uint32_t :24; + uint32_t DB3 :1; /* DMABUF 3 */ + uint32_t DB2 :1; /* DMABUF 2 */ + uint32_t DB1 :1; /* DMABUF 1 */ + uint32_t DB0 :1; /* DMABUF 0 */ + uint32_t :3; + uint32_t RST :1; /* Reset */ + ); + uint32_t const SPUADR; /* SPU address */ + uint32_t const ENDIAN; /* SuperHyway endian */ + pad(0x10); + + uint32_t GCOM[8]; /* Global Common */ + pad(0x20); + + uint32_t const DMABUF[4]; /* Inter-DSP Communication Buffer */ + +} GPACKED(4) spu_t; + +typedef volatile struct +{ + uint32_t SBAR; /* Source base address */ + uint32_t SAR; /* Source address */ + uint32_t DBAR; /* Destination base address */ + uint32_t DAR; /* Destination address */ + uint32_t TCR; /* Transfer count */ + uint32_t SHPRI; /* SHway priority */ + uint32_t CHCR; /* Channel control */ + pad(0x4); + +} GPACKED(4) spu_dsp_dma_t; + +typedef volatile struct { + uint32_t LSA; /* Loop start address */ + uint32_t LEA; /* Loop end address */ + pad(0x8); + +} GPACKED(4) spu_dsp_loop_t; + +typedef volatile struct +{ + uint32_t DSPRST; /* DSP full reset */ + uint32_t DSPCORERST; /* DSP core reset */ + uint32_t const DSPHOLD; /* DSP hold */ + uint32_t DSPRESTART; /* DSP restart */ + pad(0x8); + + uint32_t IEMASKC; /* CPU interrupt source mask */ + uint32_t IMASKC; /* CPU interrupt signal mask */ + uint32_t IEVENTC; /* CPU interrupt source */ + uint32_t IEMASKD; /* DSP interrupt source mask */ + uint32_t IMASKD; /* DSP interrupt signal mask */ + uint32_t IESETD; /* DSP interrupt set */ + uint32_t IECLRD; /* DSP interrupt clear */ + uint32_t OR; /* DMAC operation */ + uint32_t COM[8]; /* CPU-DSP communication */ + uint32_t BTADRU; /* Bus-through address high */ + uint32_t BTADRL; /* Bus-through address low */ + uint32_t WDATU; /* Bus-through write data high */ + uint32_t WDATL; /* Bus-through write data low */ + uint32_t RDATU; /* Bus-through read data high */ + uint32_t RDATL; /* Bus-through read data low */ + uint32_t BTCTRL; /* Bus-through mode control */ + uint32_t SPUSTS; /* SPU status */ + pad(0x88); + + spu_dsp_dma_t DMA[3]; + pad(0x20); + spu_dsp_loop_t LP[3]; + +} GPACKED(4) spu_dsp_t; + +#define SH7305_SPU (*(spu_t *)0xfe2ffc00) +#define SH7305_DSP0 (*(spu_dsp_t *)0xfe2ffd00) +#define SH7305_DSP1 (*(spu_dsp_t *)0xfe3ffd00) + +#endif /* GINT_MPU_SPU */ diff --git a/src/intc/intc.c b/src/intc/intc.c index 4e1b7ea..9ebee1e 100644 --- a/src/intc/intc.c +++ b/src/intc/intc.c @@ -56,6 +56,9 @@ static struct info { { IPRK, 0xf000, IMR10, 0x04, IPRA, 0x000f }, { IPRK, 0xf000, IMR10, 0x02, IPRA, 0x000f }, { IPRK, 0xf000, IMR10, 0x01, IPRA, 0x000f }, + /* SPU */ + { IPRC, 0x000f, IMR3, 0x04, _ /* Not supported on SH3! */ }, + { IPRC, 0x000f, IMR4, 0x08, _ }, }; diff --git a/src/spu/spu.c b/src/spu/spu.c new file mode 100644 index 0000000..aa87071 --- /dev/null +++ b/src/spu/spu.c @@ -0,0 +1,91 @@ +#include +#include +#include +#include +#include +#include + +#define SPU SH7305_SPU +#define DSP0 SH7305_DSP0 +#define DSP1 SH7305_DSP1 +#define CPG SH7305_CPG +#define POWER SH7305_POWER + +static void init(void) +{ + /* Block SPU interrupts from DSP0, DSP1, and their DMA */ + intc_priority(INTC_SPU_DSP0, 0); + intc_priority(INTC_SPU_DSP1, 0); + + /* Stop both the SPU and FSI clocks */ + CPG.FSICLKCR.lword = 0x00000103; + CPG.SPUCLKCR.lword = 0x00000100; + /* Enable the FSI clock, then the SPU/SPURAM clock */ + CPG.FSICLKCR.CLKSTP = 0; + CPG.SPUCLKCR.CLKSTP = 0; + + /* Power the clocks through MSTPCR2 */ + POWER.MSTPCR2.FSI_SPU = 0; + + /* Reset the SPU */ + SPU.SPUSRST.RST = 0; + SPU.SPUSRST.RST = 1; + sleep_us_spin(1000); + + /* Perform full DSP resets */ + DSP0.DSPCORERST = 1; + DSP1.DSPCORERST = 1; + DSP0.DSPRST = 0; + DSP1.DSPRST = 0; + sleep_us_spin(1000); +} + +int spu_zero(void) +{ + return 0; +} + +//--- +// Hardware context +//--- + +typedef struct +{ + uint32_t PBANKC0, PBANKC1; + uint32_t XBANKC0, XBANKC1; +} ctx_t; + +GBSS static ctx_t sys_ctx, gint_ctx; + +static void ctx_save(void *buf) +{ + ctx_t *ctx = buf; + ctx->PBANKC0 = SPU.PBANKC0; + ctx->PBANKC1 = SPU.PBANKC1; + ctx->XBANKC0 = SPU.XBANKC0; + ctx->XBANKC1 = SPU.XBANKC1; +} + +static void ctx_restore(void *buf) +{ + ctx_t *ctx = buf; + SPU.PBANKC0 = ctx->PBANKC0; + SPU.PBANKC1 = ctx->PBANKC1; + SPU.XBANKC0 = ctx->XBANKC0; + SPU.XBANKC1 = ctx->XBANKC1; +} + +//--- +// Driver structure definition +//--- + +gint_driver_t drv_spu = { + .name = "SPU", + .init = init, + .sys_ctx = &sys_ctx, + .gint_ctx = &gint_ctx, + .ctx_save = ctx_save, + .ctx_restore = ctx_restore, +}; + +GINT_DECLARE_DRIVER(3, drv_spu);