refactored SPI and CODEC drivers, getting ready to move all SPI ops to the ARM11

This commit is contained in:
Wolfvak 2019-04-21 20:30:28 -03:00 committed by d0k3
parent 1b04ca4fa1
commit b52bf3b9a5
3 changed files with 87 additions and 125 deletions

View File

@ -25,32 +25,16 @@
#define CPAD_FACTOR (150)
/* SPI stuff */
static void CODEC_DualTX(u8 *tx0, u8 len0, u8 *tx1, u8 len1)
static void CODEC_WriteRead(u32 *txb, u8 txl, u32 *rxb, u8 rxl)
{
SPI_XferInfo xfers[2];
xfers[0].buf = (u32*)tx0;
xfers[0].len = len0;
xfers[0].buf = txb;
xfers[0].len = txl;
xfers[0].read = false;
xfers[1].buf = (u32*)tx1;
xfers[1].len = len1;
xfers[1].read = false;
SPI_DoXfer(CODEC_SPI_DEV, xfers, 2);
}
static void CODEC_WriteRead(u8 *tx_buf, u8 tx_len,
u8 *rx_buf, u8 rx_len)
{
SPI_XferInfo xfers[2];
xfers[0].buf = (u32*)tx_buf;
xfers[0].len = tx_len;
xfers[0].read = false;
xfers[1].buf = (u32*)rx_buf;
xfers[1].len = rx_len;
xfers[1].buf = rxb;
xfers[1].len = rxl;
xfers[1].read = true;
SPI_DoXfer(CODEC_SPI_DEV, xfers, 2);
@ -58,60 +42,49 @@ static void CODEC_WriteRead(u8 *tx_buf, u8 tx_len,
static void CODEC_RegSelect(u8 reg)
{
u8 buffer1[4];
u8 buffer2[0x40];
SPI_XferInfo xfer;
u32 cmd;
buffer1[0] = 0;
buffer2[0] = reg;
cmd = reg << 8;
CODEC_DualTX(buffer1, 1, buffer2, 1);
xfer.buf = &cmd;
xfer.len = 2;
xfer.read = false;
SPI_DoXfer(CODEC_SPI_DEV, &xfer, 1);
}
static u8 CODEC_RegRead(u8 offset)
static u8 CODEC_RegRead(u8 reg)
{
u8 buffer_wr[8];
u8 buffer_rd[0x40];
buffer_wr[0] = 1 | (offset << 1);
CODEC_WriteRead(buffer_wr, 1, buffer_rd, 1);
return buffer_rd[0];
u32 cmd, ret;
cmd = (reg << 1) | 1;
CODEC_WriteRead(&cmd, 1, &ret, 1);
return ret;
}
static void CODEC_RegWrite(u8 reg, u8 val)
{
u8 buffer1[8];
u8 buffer2[0x40];
SPI_XferInfo xfer;
u32 cmd;
buffer1[0] = (reg << 1); // Write
buffer2[0] = val;
cmd = (val << 8) | (reg << 1);
CODEC_DualTX(buffer1, 1, buffer2, 1);
xfer.buf = &cmd;
xfer.len = 2;
xfer.read = false;
SPI_DoXfer(CODEC_SPI_DEV, &xfer, 1);
}
static void CODEC_RegReadBuf(u8 offset, void *buffer, u8 size)
static void CODEC_RegReadBuf(u8 reg, u32 *out, u8 size)
{
u8 buffer_wr[0x10];
buffer_wr[0] = 1 | (offset << 1);
CODEC_WriteRead(buffer_wr, 1, buffer, size);
u32 cmd = (reg << 1) | 1;
CODEC_WriteRead(&cmd, 1, out, size);
}
static void CODEC_RegMask(u8 offset, u8 mask0, u8 mask1)
static void CODEC_RegMask(u8 reg, u8 mask0, u8 mask1)
{
u8 buffer1[4];
u8 buffer2[0x40];
buffer1[0] = 1 | (offset << 1);
CODEC_WriteRead(buffer1, 1, buffer2, 1);
buffer1[0] = offset << 1;
buffer2[0] = (buffer2[0] & ~mask1) | (mask0 & mask1);
CODEC_DualTX(buffer1, 1, buffer2, 1);
CODEC_RegWrite(reg, (CODEC_RegRead(reg) & ~mask1) | (mask0 & mask1));
}
void CODEC_Init(void)
@ -147,7 +120,7 @@ void CODEC_Init(void)
CODEC_RegMask(0x25, 0x10, 0x3C);
}
static void CODEC_GetRawData(u8 *buffer)
void CODEC_GetRawData(u32 *buffer)
{
CODEC_RegSelect(0x67);
CODEC_RegRead(0x26);
@ -157,11 +130,12 @@ static void CODEC_GetRawData(u8 *buffer)
void CODEC_Get(CODEC_Input *input)
{
u8 raw_data[0x34];
u32 raw_data_buf[0x34 / 4];
u8 *raw_data = (u8*)raw_data_buf;
s16 cpad_x, cpad_y;
bool ts_pressed;
CODEC_GetRawData(raw_data);
CODEC_GetRawData(raw_data_buf);
cpad_x = ((raw_data[0x24] << 8 | raw_data[0x25]) & 0xFFF) - 2048;
cpad_y = ((raw_data[0x14] << 8 | raw_data[0x15]) & 0xFFF) - 2048;

View File

@ -9,4 +9,5 @@ typedef struct {
void CODEC_Init(void);
void CODEC_GetRawData(u32 *buffer);
void CODEC_Get(CODEC_Input *input);

View File

@ -15,83 +15,73 @@
#include "hw/spi.h"
#define CFG_SPI_CNT ((vu32*)0x101401C0)
#define REG_CFG_SPI_CNT ((vu16*)0x101401C0)
// TODO: CURRENTLY HARDCODED FOR DEVICE 3 (TOUCHSCREEN)
// IF ANY OTHER DEVICES ARE TO BE USED, ANOTHER BUS MUST
// BE ACCESSED, CHECK 3dbrew.org/wiki/SPI_{Registers, Services}
static const u32 SPI_Buses[] = { 0x10142800 };
#define REG_SPI(b, n) (*(vu32*)(SPI_Buses[b] + (n)))
#define REG_SPI(bus, reg) (*((vu32*)((bus) + (reg))))
#define REG_SPI_CNT REG_SPI(0, 0x00)
#define REG_SPI_DONE REG_SPI(0, 0x04)
#define REG_SPI_BLKLEN REG_SPI(0, 0x08)
#define REG_SPI_FIFO REG_SPI(0, 0x0C)
#define REG_SPI_STATUS REG_SPI(0, 0x10)
#define REG_SPI_BUS0 (0x10160800)
#define REG_SPI_BUS1 (0x10142800)
#define REG_SPI_BUS2 (0x10143800)
#define SPI_CNT_BUSY BIT(15)
#define SPI_CNT_START BIT(15)
#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_CNT_READ (0)
#define SPI_CNT_WRITE BIT(13)
#define SPI_CNT_RATE(n) (n)
#define SPI_CNT_CS(n) ((n) << 6)
#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 u8 SPI_GetDevSelect(u32 dev)
static struct {
u32 bus;
u32 regcfg;
} SPI_Devices[] = {
{REG_SPI_BUS0, SPI_CONTROL_RATE(2) | SPI_CONTROL_CS(0)}, // device 0
{REG_SPI_BUS0, SPI_CONTROL_RATE(0) | SPI_CONTROL_CS(1)},
{REG_SPI_BUS0, SPI_CONTROL_RATE(0) | SPI_CONTROL_CS(2)},
{REG_SPI_BUS1, SPI_CONTROL_RATE(5) | SPI_CONTROL_CS(0)},
// TODO: complete this table
};
static void SPI_WaitBusy(u32 bus)
{
static const u8 SPI_DevSelect[] = { 0, 1, 2, 0, 1, 2 };
if (dev < countof(SPI_DevSelect)) {
return SPI_DevSelect[dev];
} else {
return 0;
}
while(REG_SPI(bus, REG_SPI_CONTROL) & SPI_CONTROL_BUSY);
}
static u8 SPI_GetDevBaudrate(u32 dev)
static void SPI_WaitFIFO(u32 bus)
{
static const u8 SPI_BaudRates[] = { 2, 0, 0, 5 };
if (dev < countof(SPI_BaudRates)) {
return SPI_BaudRates[dev];
} else {
return 0;
}
while(REG_SPI(bus, REG_SPI_STAT) & SPI_STAT_BUSY);
}
static void SPI_WaitBusy(void)
static void SPI_Done(u32 bus)
{
while(REG_SPI_CNT & SPI_CNT_BUSY);
REG_SPI(bus, REG_SPI_DONE) = 0;
}
static void SPI_WaitFIFO(void)
{
while(REG_SPI_STATUS & SPI_STAT_BUSY);
}
static void SPI_Done(void)
{
REG_SPI_DONE = 0;
}
static void SPI_SingleXfer(u32 reg, bool read, u32 *buffer, u32 len)
static void SPI_SingleXfer(u32 reg, u32 bus, u32 *buffer, u32 len, bool read)
{
u32 pos = 0;
REG_SPI_BLKLEN = len;
REG_SPI_CNT = reg | (read ? SPI_CNT_READ : SPI_CNT_WRITE) | SPI_CNT_START;
REG_SPI(bus, REG_SPI_BLKLEN) = len;
REG_SPI(bus, REG_SPI_CONTROL) = reg |
(read ? SPI_DIRECTION_READ : SPI_DIRECTION_WRITE) | SPI_CONTROL_START;
do {
if ((pos % SPI_FIFO_WIDTH) == 0)
SPI_WaitFIFO();
SPI_WaitFIFO(bus);
if (read) {
buffer[pos / 4] = REG_SPI_FIFO;
buffer[pos / 4] = REG_SPI(bus, REG_SPI_FIFO);
} else {
REG_SPI_FIFO = buffer[pos / 4];
REG_SPI(bus, REG_SPI_FIFO) = buffer[pos / 4];
}
pos += 4;
@ -100,30 +90,27 @@ static void SPI_SingleXfer(u32 reg, bool read, u32 *buffer, u32 len)
int SPI_DoXfer(u32 dev, SPI_XferInfo *xfers, u32 xfer_cnt)
{
u32 dev_cfg;
int baud, cs;
u32 bus;
u32 dev_reg;
baud = SPI_GetDevBaudrate(dev);
cs = SPI_GetDevSelect(dev);
dev_cfg = SPI_CNT_RATE(baud) | SPI_CNT_CS(cs);
bus = SPI_Devices[dev].bus;
dev_reg = SPI_Devices[dev].regcfg;
for (u32 i = 0; i < xfer_cnt; i++) {
SPI_XferInfo *xfer = &xfers[i];
SPI_WaitBusy();
SPI_SingleXfer(dev_cfg, xfer->read, xfer->buf, xfer->len);
SPI_WaitBusy(bus);
SPI_SingleXfer(dev_reg, bus, xfer->buf, xfer->len, xfer->read);
}
SPI_WaitBusy();
SPI_Done();
SPI_WaitBusy(bus);
SPI_Done(bus);
return 0;
}
void SPI_Init(void)
{
// Hack: here all registers should be set to the "new" mode
// but GM9 uses the old interface to access NVRAM
// as such, only the bus used by CODEC will be set to new
// *CFG_SPI_CNT = 7;
*CFG_SPI_CNT = BIT(1);
// This cuts off access from the old SPI
// interface used during the NDS days
*REG_CFG_SPI_CNT = 7;
}