mirror of
https://github.com/d0k3/GodMode9.git
synced 2025-06-25 21:22:47 +00:00
Merge ARM11 spi and ARM9 spicard drivers
Also centralize device IDs into SPI.h
This commit is contained in:
parent
48d8c48d12
commit
d2f596e7a3
@ -24,9 +24,7 @@
|
||||
#include <hid_map.h>
|
||||
|
||||
#include "hw/codec.h"
|
||||
#include "hw/spi.h"
|
||||
|
||||
#define CODEC_SPI_DEV 3
|
||||
#include <spi.h>
|
||||
|
||||
#define CPAD_THRESH_X (750)
|
||||
#define CPAD_THRESH_Y (150)
|
||||
@ -44,7 +42,7 @@ static void CODEC_WriteRead(u32 *txb, u8 txl, u32 *rxb, u8 rxl)
|
||||
xfers[1].len = rxl;
|
||||
xfers[1].read = true;
|
||||
|
||||
SPI_DoXfer(CODEC_SPI_DEV, xfers, 2);
|
||||
SPI_DoXfer(SPI_DEV_CODEC, xfers, 2, true);
|
||||
}
|
||||
|
||||
static void CODEC_RegSelect(u8 reg)
|
||||
@ -58,7 +56,7 @@ static void CODEC_RegSelect(u8 reg)
|
||||
xfer.len = 2;
|
||||
xfer.read = false;
|
||||
|
||||
SPI_DoXfer(CODEC_SPI_DEV, &xfer, 1);
|
||||
SPI_DoXfer(SPI_DEV_CODEC, &xfer, 1, true);
|
||||
}
|
||||
|
||||
static u8 CODEC_RegRead(u8 reg)
|
||||
@ -86,7 +84,7 @@ static void CODEC_RegWrite(u8 reg, u8 val)
|
||||
xfer.len = 2;
|
||||
xfer.read = false;
|
||||
|
||||
SPI_DoXfer(CODEC_SPI_DEV, &xfer, 1);
|
||||
SPI_DoXfer(SPI_DEV_CODEC, &xfer, 1, true);
|
||||
}
|
||||
|
||||
static void CODEC_RegMask(u8 reg, u8 mask0, u8 mask1)
|
||||
|
@ -18,11 +18,9 @@
|
||||
|
||||
#include <types.h>
|
||||
|
||||
#include "hw/spi.h"
|
||||
#include <spi.h>
|
||||
#include "hw/nvram.h"
|
||||
|
||||
#define NVRAM_SPI_DEV 1
|
||||
|
||||
// returns manuf id, memory type and size
|
||||
// size = (1 << id[2]) ?
|
||||
// apparently unreliable on some Sanyo chips?
|
||||
@ -51,7 +49,7 @@ static u32 NVRAM_SendStatusCommand(u32 cmd, u32 width)
|
||||
xfer[1].read = true;
|
||||
|
||||
ret = 0;
|
||||
SPI_DoXfer(NVRAM_SPI_DEV, xfer, 2);
|
||||
SPI_DoXfer(SPI_DEV_NVRAM, xfer, 2, true);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -91,5 +89,5 @@ void NVRAM_Read(u32 address, u32 *buffer, u32 len)
|
||||
xfer[1].len = len;
|
||||
xfer[1].read = true;
|
||||
|
||||
SPI_DoXfer(NVRAM_SPI_DEV, xfer, 2);
|
||||
SPI_DoXfer(SPI_DEV_NVRAM, xfer, 2, true);
|
||||
}
|
||||
|
@ -20,7 +20,7 @@
|
||||
|
||||
#include <types.h>
|
||||
|
||||
#include "hw/spi.h"
|
||||
#include <spi.h>
|
||||
|
||||
#define NVRAM_SR_WIP BIT(0) // work in progress / busy
|
||||
#define NVRAM_SR_WEL BIT(1) // write enable latch
|
||||
|
@ -30,7 +30,7 @@
|
||||
#include "hw/gpulcd.h"
|
||||
#include "hw/i2c.h"
|
||||
#include "hw/mcu.h"
|
||||
#include "hw/spi.h"
|
||||
#include <spi.h>
|
||||
|
||||
#include "system/sections.h"
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
||||
*/
|
||||
|
||||
#include "spi.h"
|
||||
#include "spicard.h"
|
||||
#include <spi.h>
|
||||
#include "timer.h"
|
||||
|
||||
// declarations for actual implementations
|
||||
@ -103,19 +103,27 @@ const CardType FLASH_256KB_2_INFRARED = FlashInfraredTypes + 1;
|
||||
const CardType FLASH_512KB_1_INFRARED = FlashInfraredTypes + 2;
|
||||
const CardType FLASH_512KB_2_INFRARED = FlashInfraredTypes + 3;
|
||||
|
||||
int SPIWriteRead(CardType type, void* cmd, u32 cmdSize, void* answer, u32 answerSize, const void* data, u32 dataSize) {
|
||||
const u32 headerFooterVal = 0;
|
||||
bool b = type->infrared;
|
||||
#define REG_CFG9_CARDCTL *((vu16*)0x1000000C)
|
||||
#define CARDCTL_SPICARD (1u<<8)
|
||||
|
||||
SPICARD_init();
|
||||
int SPIWriteRead(CardType type, const void* cmd, u32 cmdSize, void* answer, u32 answerSize, const void* data, u32 dataSize) {
|
||||
u32 headerFooterVal = 0;
|
||||
|
||||
if (b) {
|
||||
SPICARD_writeRead(NSPI_CLK_1MHz, &headerFooterVal, NULL, 1, 0, false);
|
||||
REG_CFG9_CARDCTL |= CARDCTL_SPICARD;
|
||||
|
||||
if (type->infrared) {
|
||||
SPI_XferInfo irXfer = { &headerFooterVal, 1, false };
|
||||
SPI_DoXfer(SPI_DEV_CART_IR, &irXfer, 1, false);
|
||||
}
|
||||
SPICARD_writeRead(NSPI_CLK_4MHz, cmd, answer, cmdSize, answerSize, false);
|
||||
SPICARD_writeRead(NSPI_CLK_4MHz, data, NULL, dataSize, 0, true);
|
||||
|
||||
SPICARD_deinit();
|
||||
SPI_XferInfo transfers[3] = {
|
||||
{ (u8*) cmd, cmdSize, false },
|
||||
{ answer, answerSize, true },
|
||||
{ (u8*) data, dataSize, false },
|
||||
};
|
||||
SPI_DoXfer(SPI_DEV_CART_FLASH, transfers, 3, true);
|
||||
|
||||
REG_CFG9_CARDCTL &= ~CARDCTL_SPICARD;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -97,7 +97,7 @@ const CardType FLASH_256KB_2_INFRARED;
|
||||
const CardType FLASH_512KB_1_INFRARED;
|
||||
const CardType FLASH_512KB_2_INFRARED;
|
||||
|
||||
int SPIWriteRead(CardType type, void* cmd, u32 cmdSize, void* answer, u32 answerSize, const void* data, u32 dataSize);
|
||||
int SPIWriteRead(CardType type, const void* cmd, u32 cmdSize, void* answer, u32 answerSize, const void* data, u32 dataSize);
|
||||
int SPIWaitWriteEnd(CardType type);
|
||||
int SPIEnableWriting(CardType type);
|
||||
int SPIReadJEDECIDAndStatusReg(CardType type, u32* id, u8* statusReg);
|
||||
|
@ -1,120 +0,0 @@
|
||||
/*
|
||||
* This file is part of fastboot 3DS
|
||||
* Copyright (C) 2019 derrek, profi200
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "types.h"
|
||||
#include "spicard.h"
|
||||
#include "delay.h"
|
||||
|
||||
#define REG_CFG9_CARDCTL *((vu16*)0x1000000C)
|
||||
|
||||
#define SPICARD_REGS_BASE 0x1000D800
|
||||
#define REG_NSPI_CNT *((vu32*)(SPICARD_REGS_BASE + 0x00))
|
||||
#define REG_NSPI_DONE *((vu32*)(SPICARD_REGS_BASE + 0x04))
|
||||
#define REG_NSPI_BLKLEN *((vu32*)(SPICARD_REGS_BASE + 0x08))
|
||||
#define REG_NSPI_FIFO *((vu32*)(SPICARD_REGS_BASE + 0x0C))
|
||||
#define REG_NSPI_STATUS *((vu32*)(SPICARD_REGS_BASE + 0x10))
|
||||
#define REG_NSPI_AUTOPOLL *((vu32*)(SPICARD_REGS_BASE + 0x14))
|
||||
#define REG_NSPI_INT_MASK *((vu32*)(SPICARD_REGS_BASE + 0x18))
|
||||
#define REG_NSPI_INT_STAT *((vu32*)(SPICARD_REGS_BASE + 0x1C))
|
||||
|
||||
|
||||
|
||||
static inline void nspiWaitBusy(void)
|
||||
{
|
||||
while(REG_NSPI_CNT & NSPI_CNT_ENABLE);
|
||||
}
|
||||
|
||||
static inline void nspiWaitFifoBusy(void)
|
||||
{
|
||||
while(REG_NSPI_STATUS & NSPI_STATUS_BUSY);
|
||||
}
|
||||
|
||||
void SPICARD_init(void)
|
||||
{
|
||||
REG_CFG9_CARDCTL |= 1u<<8;
|
||||
}
|
||||
|
||||
void SPICARD_deinit(void)
|
||||
{
|
||||
REG_CFG9_CARDCTL &= ~(1u<<8);
|
||||
}
|
||||
|
||||
/*
|
||||
bool _SPICARD_autoPollBit(u32 params)
|
||||
{
|
||||
REG_NSPI_AUTOPOLL = NSPI_AUTOPOLL_START | params;
|
||||
|
||||
u32 res;
|
||||
do
|
||||
{
|
||||
__wfi();
|
||||
res = REG_NSPI_INT_STAT;
|
||||
} while(!(res & (NSPI_INT_AP_TIMEOUT | NSPI_INT_AP_SUCCESS)));
|
||||
REG_NSPI_INT_STAT = res; // Aknowledge
|
||||
|
||||
return (res & NSPI_INT_AP_TIMEOUT) == 0; // Timeout error
|
||||
}
|
||||
*/
|
||||
|
||||
void SPICARD_writeRead(NspiClk clk, const void *in, void *out, u32 inSize, u32 outSize, bool done)
|
||||
{
|
||||
const u32 cntParams = NSPI_CNT_ENABLE | NSPI_CNT_BUS_1BIT | clk;
|
||||
|
||||
REG_CFG9_CARDCTL |= 1u<<8;
|
||||
|
||||
u32 buf;
|
||||
char *in_ = (char *) in;
|
||||
char *out_ = (char *) out;
|
||||
|
||||
if(in_)
|
||||
{
|
||||
REG_NSPI_BLKLEN = inSize;
|
||||
REG_NSPI_CNT = cntParams | NSPI_CNT_DIRE_WRITE;
|
||||
|
||||
u32 counter = 0;
|
||||
do
|
||||
{
|
||||
if((counter & 31) == 0) nspiWaitFifoBusy();
|
||||
memcpy(&buf, in_, min(4, inSize - counter));
|
||||
REG_NSPI_FIFO = buf;
|
||||
counter += 4;
|
||||
in_ += 4;
|
||||
} while(counter < inSize);
|
||||
|
||||
nspiWaitBusy();
|
||||
}
|
||||
if(out_)
|
||||
{
|
||||
REG_NSPI_BLKLEN = outSize;
|
||||
REG_NSPI_CNT = cntParams | NSPI_CNT_DIRE_READ;
|
||||
|
||||
u32 counter = 0;
|
||||
do
|
||||
{
|
||||
if((counter & 31) == 0) nspiWaitFifoBusy();
|
||||
buf = REG_NSPI_FIFO;
|
||||
memcpy(out_, &buf, min(4, outSize - counter));
|
||||
counter += 4;
|
||||
out_ += 4;
|
||||
} while(counter < outSize);
|
||||
|
||||
nspiWaitBusy();
|
||||
}
|
||||
|
||||
if(done) REG_NSPI_DONE = NSPI_DONE;
|
||||
}
|
@ -1,101 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
* This file is part of fastboot 3DS
|
||||
* Copyright (C) 2019 derrek, profi200
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "types.h"
|
||||
|
||||
|
||||
// REG_NSPI_CNT
|
||||
#define NSPI_CNT_BUS_1BIT (0u)
|
||||
#define NSPI_CNT_BUS_4BIT (1u<<12)
|
||||
#define NSPI_CNT_DIRE_READ (0u)
|
||||
#define NSPI_CNT_DIRE_WRITE (1u<<13)
|
||||
#define NSPI_CNT_ENABLE (1u<<15)
|
||||
|
||||
// REG_NSPI_DONE
|
||||
#define NSPI_DONE (0u)
|
||||
|
||||
// REG_NSPI_STATUS
|
||||
#define NSPI_STATUS_BUSY (1u)
|
||||
|
||||
// REG_NSPI_AUTOPOLL
|
||||
#define NSPI_AUTOPOLL_START (1u<<31)
|
||||
|
||||
// REG_NSPI_INT_MASK Bit set = disabled.
|
||||
// REG_NSPI_INT_STAT Status and aknowledge.
|
||||
#define NSPI_INT_TRANSF_END (1u) // Fires on (each?) auto poll try aswell
|
||||
#define NSPI_INT_AP_SUCCESS (1u<<1) // Auto poll
|
||||
#define NSPI_INT_AP_TIMEOUT (1u<<2) // Auto poll
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
NSPI_CLK_512KHz = 0u,
|
||||
NSPI_CLK_1MHz = 1u,
|
||||
NSPI_CLK_2MHz = 2u,
|
||||
NSPI_CLK_4MHz = 3u,
|
||||
NSPI_CLK_8MHz = 4u,
|
||||
NSPI_CLK_16MHz = 5u
|
||||
} NspiClk;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Activates the SPI bus. Use after some cartridge interface has been initialized.
|
||||
*/
|
||||
void SPICARD_init(void);
|
||||
|
||||
/**
|
||||
* @brief Deactivates the SPI bus.
|
||||
*/
|
||||
void SPICARD_deinit(void);
|
||||
|
||||
/**
|
||||
* @brief Automatically polls a bit of the command response. Use with the macro below.
|
||||
*
|
||||
* @param[in] params The parameters. Use the macro below.
|
||||
*
|
||||
* @return Returns false on failure/timeout and true on success.
|
||||
*/
|
||||
bool _SPICARD_autoPollBit(u32 params);
|
||||
|
||||
/**
|
||||
* @brief Writes and/or reads data to/from a SPI device.
|
||||
*
|
||||
* @param[in] clk The clock frequency to use.
|
||||
* @param[in] in Input data pointer for write.
|
||||
* @param out Output data pointer for read.
|
||||
* @param[in] inSize Input size. Must be <= 0x1FFFFF.
|
||||
* @param[in] outSize Output size. Must be <= 0x1FFFFF.
|
||||
* @param[in] done Set to true if this is the last transfer (chip select).
|
||||
*/
|
||||
void SPICARD_writeRead(NspiClk clk, const void *in, void *out, u32 inSize, u32 outSize, bool done);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Automatically polls a bit of the command response.
|
||||
*
|
||||
* @param[in] cmd The command.
|
||||
* @param[in] timeout The timeout. Must be 0-15. Tries = 31<<NspiClk + timeout.
|
||||
* @param[in] off The bit offset. Must be 0-7.
|
||||
* @param[in] bitSet Poll for a set ur unset bit.
|
||||
*
|
||||
* @return Returns false on failure/timeout and true on success.
|
||||
*/
|
||||
#define SPICARD_autoPollBit(cmd, timeout, off, bitSet) _SPICARD_autoPollBit((bitSet)<<30 | (off)<<24 | (timeout)<<16 | (cmd))
|
@ -1,134 +1,151 @@
|
||||
// Somewhat based on xerpi's SPI driver for Linux
|
||||
/*
|
||||
* This file is part of GodMode9
|
||||
* Copyright (C) 2016 Sergi Granell
|
||||
* Copyright (C) 2019 Wolfvak
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <types.h>
|
||||
|
||||
#include "hw/spi.h"
|
||||
|
||||
#define REG_CFG_SPI_CNT ((vu16*)0x101401C0)
|
||||
|
||||
#define REG_SPI(bus, reg) (*((vu32*)((bus) + (reg))))
|
||||
|
||||
#define REG_SPI_BUS0 (0x10160800)
|
||||
#define REG_SPI_BUS1 (0x10142800)
|
||||
#define REG_SPI_BUS2 (0x10143800)
|
||||
|
||||
#define REG_SPI_CONTROL 0x00
|
||||
#define REG_SPI_DONE 0x04
|
||||
#define REG_SPI_BLKLEN 0x08
|
||||
#define REG_SPI_FIFO 0x0C
|
||||
#define REG_SPI_STAT 0x10
|
||||
|
||||
#define SPI_CONTROL_RATE(n) (n)
|
||||
#define SPI_CONTROL_CS(n) ((n) << 6)
|
||||
#define SPI_DIRECTION_READ (0)
|
||||
#define SPI_DIRECTION_WRITE BIT(13)
|
||||
#define SPI_CONTROL_BUSY BIT(15)
|
||||
#define SPI_CONTROL_START BIT(15)
|
||||
|
||||
#define SPI_STAT_BUSY BIT(0)
|
||||
|
||||
#define SPI_FIFO_WIDTH (32)
|
||||
|
||||
static struct {
|
||||
u32 bus;
|
||||
u32 reg;
|
||||
} SPI_Devices[] = {
|
||||
{REG_SPI_BUS0, SPI_CONTROL_RATE(2) | SPI_CONTROL_CS(0)},
|
||||
{REG_SPI_BUS0, SPI_CONTROL_RATE(0) | SPI_CONTROL_CS(1)}, // NVRAM
|
||||
{REG_SPI_BUS0, SPI_CONTROL_RATE(0) | SPI_CONTROL_CS(2)},
|
||||
{REG_SPI_BUS1, SPI_CONTROL_RATE(5) | SPI_CONTROL_CS(0)}, // CODEC
|
||||
// TODO: complete this table
|
||||
};
|
||||
|
||||
static void SPI_WaitBusy(u32 bus)
|
||||
{
|
||||
while(REG_SPI(bus, REG_SPI_CONTROL) & SPI_CONTROL_BUSY);
|
||||
}
|
||||
|
||||
static void SPI_WaitFIFO(u32 bus)
|
||||
{
|
||||
while(REG_SPI(bus, REG_SPI_STAT) & SPI_STAT_BUSY);
|
||||
}
|
||||
|
||||
static void SPI_Done(u32 bus)
|
||||
{
|
||||
REG_SPI(bus, REG_SPI_DONE) = 0;
|
||||
}
|
||||
|
||||
static void SPI_SingleXfer(u32 reg, u32 bus, u32 *buffer, u32 len, bool read)
|
||||
{
|
||||
u32 pos = 0;
|
||||
|
||||
REG_SPI(bus, REG_SPI_BLKLEN) = len;
|
||||
REG_SPI(bus, REG_SPI_CONTROL) = reg |
|
||||
(read ? SPI_DIRECTION_READ : SPI_DIRECTION_WRITE) | SPI_CONTROL_START;
|
||||
|
||||
SPI_WaitFIFO(bus);
|
||||
|
||||
do {
|
||||
if ((pos % SPI_FIFO_WIDTH) == 0)
|
||||
SPI_WaitFIFO(bus);
|
||||
|
||||
if (read) {
|
||||
buffer[pos / 4] = REG_SPI(bus, REG_SPI_FIFO);
|
||||
} else {
|
||||
REG_SPI(bus, REG_SPI_FIFO) = buffer[pos / 4];
|
||||
}
|
||||
|
||||
pos += 4;
|
||||
} while(pos < len);
|
||||
}
|
||||
|
||||
int SPI_DoXfer(u32 dev, const SPI_XferInfo *xfers, u32 xfer_cnt)
|
||||
{
|
||||
u32 bus, reg;
|
||||
|
||||
bus = SPI_Devices[dev].bus;
|
||||
reg = SPI_Devices[dev].reg;
|
||||
|
||||
for (u32 i = 0; i < xfer_cnt; i++) {
|
||||
const SPI_XferInfo *xfer = &xfers[i];
|
||||
|
||||
if (!xfer->buf || !xfer->len)
|
||||
continue;
|
||||
|
||||
SPI_WaitBusy(bus);
|
||||
SPI_SingleXfer(reg, bus, xfer->buf, xfer->len, xfer->read);
|
||||
}
|
||||
|
||||
SPI_WaitBusy(bus);
|
||||
SPI_Done(bus);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SPI_Init(void)
|
||||
{
|
||||
// This cuts off access to the old NDS SPI interface
|
||||
*REG_CFG_SPI_CNT = 7;
|
||||
}
|
||||
|
||||
void SPI_Deinit(void)
|
||||
{
|
||||
// Keep backwards compatibility with software that
|
||||
// assumes all bus interfaces will be set to old
|
||||
*REG_CFG_SPI_CNT = 0;
|
||||
}
|
||||
// Somewhat based on xerpi's SPI driver for Linux
|
||||
/*
|
||||
* This file is part of GodMode9
|
||||
* Copyright (C) 2016 Sergi Granell
|
||||
* Copyright (C) 2019 Wolfvak
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <types.h>
|
||||
|
||||
#include "spi.h"
|
||||
|
||||
#define REG_CFG_SPI_CNT ((vu16*)0x101401C0)
|
||||
|
||||
#define REG_SPI(bus, reg) (*((vu32*)((bus) + (reg))))
|
||||
|
||||
#define REG_SPI_BUS0 (0x10160800)
|
||||
#define REG_SPI_BUS1 (0x10142800)
|
||||
#define REG_SPI_BUS2 (0x10143800)
|
||||
#define REG_SPI_CARD (0x1000D800)
|
||||
|
||||
#define REG_SPI_CONTROL 0x00
|
||||
#define REG_SPI_DONE 0x04
|
||||
#define REG_SPI_BLKLEN 0x08
|
||||
#define REG_SPI_FIFO 0x0C
|
||||
#define REG_SPI_STAT 0x10
|
||||
|
||||
#define SPI_CONTROL_RATE(n) (n)
|
||||
#define SPI_CONTROL_CS(n) ((n) << 6)
|
||||
#define SPI_DIRECTION_READ (0)
|
||||
#define SPI_DIRECTION_WRITE BIT(13)
|
||||
#define SPI_CONTROL_BUSY BIT(15)
|
||||
#define SPI_CONTROL_START BIT(15)
|
||||
|
||||
#define SPI_STAT_BUSY BIT(0)
|
||||
|
||||
#define SPI_FIFO_WIDTH (32)
|
||||
|
||||
static struct {
|
||||
u32 bus;
|
||||
u32 reg;
|
||||
} SPI_Devices[] = {
|
||||
{REG_SPI_BUS0, SPI_CONTROL_RATE(2) | SPI_CONTROL_CS(0)},
|
||||
{REG_SPI_BUS0, SPI_CONTROL_RATE(0) | SPI_CONTROL_CS(1)}, // NVRAM
|
||||
{REG_SPI_BUS0, SPI_CONTROL_RATE(0) | SPI_CONTROL_CS(2)},
|
||||
{REG_SPI_BUS1, SPI_CONTROL_RATE(5) | SPI_CONTROL_CS(0)}, // CODEC
|
||||
{REG_SPI_CARD, SPI_CONTROL_RATE(3) | SPI_CONTROL_CS(0)}, // Gamecard flash chip
|
||||
{REG_SPI_CARD, SPI_CONTROL_RATE(1) | SPI_CONTROL_CS(0)}, // Gamecard IR chip
|
||||
// TODO: complete this table
|
||||
};
|
||||
|
||||
static void SPI_WaitBusy(u32 bus)
|
||||
{
|
||||
while(REG_SPI(bus, REG_SPI_CONTROL) & SPI_CONTROL_BUSY);
|
||||
}
|
||||
|
||||
static void SPI_WaitFIFO(u32 bus)
|
||||
{
|
||||
while(REG_SPI(bus, REG_SPI_STAT) & SPI_STAT_BUSY);
|
||||
}
|
||||
|
||||
static void SPI_Done(u32 bus)
|
||||
{
|
||||
REG_SPI(bus, REG_SPI_DONE) = 0;
|
||||
}
|
||||
|
||||
static void SPI_SingleXfer(u32 reg, u32 bus, void *buffer, u32 len, bool read)
|
||||
{
|
||||
u32 pos = 0;
|
||||
bool aligned = ((u32)buffer % 4 == 0) && (len % 4 == 0);
|
||||
|
||||
REG_SPI(bus, REG_SPI_BLKLEN) = len;
|
||||
REG_SPI(bus, REG_SPI_CONTROL) = reg |
|
||||
(read ? SPI_DIRECTION_READ : SPI_DIRECTION_WRITE) | SPI_CONTROL_START;
|
||||
|
||||
SPI_WaitFIFO(bus);
|
||||
|
||||
do {
|
||||
if ((pos % SPI_FIFO_WIDTH) == 0)
|
||||
SPI_WaitFIFO(bus);
|
||||
|
||||
if(aligned) {
|
||||
if (read) {
|
||||
((u32*)buffer)[pos / 4] = REG_SPI(bus, REG_SPI_FIFO);
|
||||
} else {
|
||||
REG_SPI(bus, REG_SPI_FIFO) = ((u32*)buffer)[pos / 4];
|
||||
}
|
||||
} else {
|
||||
if (read) {
|
||||
u32 tmp = REG_SPI(bus, REG_SPI_FIFO);
|
||||
memcpy((u8 *) buffer + pos, &tmp, min(4, len - pos));
|
||||
} else {
|
||||
u32 tmp;
|
||||
memcpy(&tmp, (u8 *) buffer + pos, min(4, len - pos));
|
||||
REG_SPI(bus, REG_SPI_FIFO) = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
pos += 4;
|
||||
} while(pos < len);
|
||||
}
|
||||
|
||||
int SPI_DoXfer(u32 dev, const SPI_XferInfo *xfers, u32 xfer_cnt, bool done)
|
||||
{
|
||||
u32 bus, reg;
|
||||
|
||||
bus = SPI_Devices[dev].bus;
|
||||
reg = SPI_Devices[dev].reg;
|
||||
|
||||
for (u32 i = 0; i < xfer_cnt; i++) {
|
||||
const SPI_XferInfo *xfer = &xfers[i];
|
||||
|
||||
if (!xfer->buf || !xfer->len)
|
||||
continue;
|
||||
|
||||
SPI_WaitBusy(bus);
|
||||
SPI_SingleXfer(reg, bus, xfer->buf, xfer->len, xfer->read);
|
||||
}
|
||||
|
||||
SPI_WaitBusy(bus);
|
||||
if(done) {
|
||||
SPI_Done(bus);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SPI_Init(void)
|
||||
{
|
||||
// This cuts off access to the old NDS SPI interface
|
||||
*REG_CFG_SPI_CNT = 7;
|
||||
}
|
||||
|
||||
void SPI_Deinit(void)
|
||||
{
|
||||
// Keep backwards compatibility with software that
|
||||
// assumes all bus interfaces will be set to old
|
||||
*REG_CFG_SPI_CNT = 0;
|
||||
}
|
@ -1,32 +1,37 @@
|
||||
/*
|
||||
* This file is part of GodMode9
|
||||
* Copyright (C) 2019 Wolfvak
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <types.h>
|
||||
|
||||
typedef struct {
|
||||
u32 *buf;
|
||||
u32 len;
|
||||
bool read;
|
||||
} SPI_XferInfo;
|
||||
|
||||
int SPI_DoXfer(u32 dev, const SPI_XferInfo *xfer, u32 xfer_cnt);
|
||||
|
||||
void SPI_Init(void);
|
||||
void SPI_Deinit(void);
|
||||
/*
|
||||
* This file is part of GodMode9
|
||||
* Copyright (C) 2019 Wolfvak
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <types.h>
|
||||
|
||||
#define SPI_DEV_NVRAM 1
|
||||
#define SPI_DEV_CODEC 3
|
||||
#define SPI_DEV_CART_FLASH 4
|
||||
#define SPI_DEV_CART_IR 5
|
||||
|
||||
typedef struct {
|
||||
void *buf;
|
||||
u32 len;
|
||||
bool read;
|
||||
} SPI_XferInfo;
|
||||
|
||||
int SPI_DoXfer(u32 dev, const SPI_XferInfo *xfer, u32 xfer_cnt, bool done);
|
||||
|
||||
void SPI_Init(void);
|
||||
void SPI_Deinit(void);
|
Loading…
x
Reference in New Issue
Block a user