mirror of
https://github.com/d0k3/GodMode9.git
synced 2025-06-26 13:42:47 +00:00
refactored SPI and CODEC drivers, getting ready to move all SPI ops to the ARM11
This commit is contained in:
parent
1b04ca4fa1
commit
b52bf3b9a5
@ -25,32 +25,16 @@
|
|||||||
#define CPAD_FACTOR (150)
|
#define CPAD_FACTOR (150)
|
||||||
|
|
||||||
/* SPI stuff */
|
/* 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];
|
SPI_XferInfo xfers[2];
|
||||||
|
|
||||||
xfers[0].buf = (u32*)tx0;
|
xfers[0].buf = txb;
|
||||||
xfers[0].len = len0;
|
xfers[0].len = txl;
|
||||||
xfers[0].read = false;
|
xfers[0].read = false;
|
||||||
|
|
||||||
xfers[1].buf = (u32*)tx1;
|
xfers[1].buf = rxb;
|
||||||
xfers[1].len = len1;
|
xfers[1].len = rxl;
|
||||||
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].read = true;
|
xfers[1].read = true;
|
||||||
|
|
||||||
SPI_DoXfer(CODEC_SPI_DEV, xfers, 2);
|
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)
|
static void CODEC_RegSelect(u8 reg)
|
||||||
{
|
{
|
||||||
u8 buffer1[4];
|
SPI_XferInfo xfer;
|
||||||
u8 buffer2[0x40];
|
u32 cmd;
|
||||||
|
|
||||||
buffer1[0] = 0;
|
cmd = reg << 8;
|
||||||
buffer2[0] = reg;
|
|
||||||
|
|
||||||
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];
|
u32 cmd, ret;
|
||||||
u8 buffer_rd[0x40];
|
cmd = (reg << 1) | 1;
|
||||||
|
CODEC_WriteRead(&cmd, 1, &ret, 1);
|
||||||
buffer_wr[0] = 1 | (offset << 1);
|
return ret;
|
||||||
|
|
||||||
CODEC_WriteRead(buffer_wr, 1, buffer_rd, 1);
|
|
||||||
|
|
||||||
return buffer_rd[0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CODEC_RegWrite(u8 reg, u8 val)
|
static void CODEC_RegWrite(u8 reg, u8 val)
|
||||||
{
|
{
|
||||||
u8 buffer1[8];
|
SPI_XferInfo xfer;
|
||||||
u8 buffer2[0x40];
|
u32 cmd;
|
||||||
|
|
||||||
buffer1[0] = (reg << 1); // Write
|
cmd = (val << 8) | (reg << 1);
|
||||||
buffer2[0] = val;
|
|
||||||
|
|
||||||
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];
|
u32 cmd = (reg << 1) | 1;
|
||||||
|
CODEC_WriteRead(&cmd, 1, out, size);
|
||||||
buffer_wr[0] = 1 | (offset << 1);
|
|
||||||
|
|
||||||
CODEC_WriteRead(buffer_wr, 1, buffer, size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CODEC_RegMask(u8 offset, u8 mask0, u8 mask1)
|
static void CODEC_RegMask(u8 reg, u8 mask0, u8 mask1)
|
||||||
{
|
{
|
||||||
u8 buffer1[4];
|
CODEC_RegWrite(reg, (CODEC_RegRead(reg) & ~mask1) | (mask0 & mask1));
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CODEC_Init(void)
|
void CODEC_Init(void)
|
||||||
@ -147,7 +120,7 @@ void CODEC_Init(void)
|
|||||||
CODEC_RegMask(0x25, 0x10, 0x3C);
|
CODEC_RegMask(0x25, 0x10, 0x3C);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CODEC_GetRawData(u8 *buffer)
|
void CODEC_GetRawData(u32 *buffer)
|
||||||
{
|
{
|
||||||
CODEC_RegSelect(0x67);
|
CODEC_RegSelect(0x67);
|
||||||
CODEC_RegRead(0x26);
|
CODEC_RegRead(0x26);
|
||||||
@ -157,11 +130,12 @@ static void CODEC_GetRawData(u8 *buffer)
|
|||||||
|
|
||||||
void CODEC_Get(CODEC_Input *input)
|
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;
|
s16 cpad_x, cpad_y;
|
||||||
bool ts_pressed;
|
bool ts_pressed;
|
||||||
|
|
||||||
CODEC_GetRawData(raw_data);
|
CODEC_GetRawData(raw_data_buf);
|
||||||
|
|
||||||
cpad_x = ((raw_data[0x24] << 8 | raw_data[0x25]) & 0xFFF) - 2048;
|
cpad_x = ((raw_data[0x24] << 8 | raw_data[0x25]) & 0xFFF) - 2048;
|
||||||
cpad_y = ((raw_data[0x14] << 8 | raw_data[0x15]) & 0xFFF) - 2048;
|
cpad_y = ((raw_data[0x14] << 8 | raw_data[0x15]) & 0xFFF) - 2048;
|
||||||
|
@ -9,4 +9,5 @@ typedef struct {
|
|||||||
|
|
||||||
void CODEC_Init(void);
|
void CODEC_Init(void);
|
||||||
|
|
||||||
|
void CODEC_GetRawData(u32 *buffer);
|
||||||
void CODEC_Get(CODEC_Input *input);
|
void CODEC_Get(CODEC_Input *input);
|
||||||
|
@ -15,83 +15,73 @@
|
|||||||
|
|
||||||
#include "hw/spi.h"
|
#include "hw/spi.h"
|
||||||
|
|
||||||
#define CFG_SPI_CNT ((vu32*)0x101401C0)
|
#define REG_CFG_SPI_CNT ((vu16*)0x101401C0)
|
||||||
|
|
||||||
// TODO: CURRENTLY HARDCODED FOR DEVICE 3 (TOUCHSCREEN)
|
#define REG_SPI(bus, reg) (*((vu32*)((bus) + (reg))))
|
||||||
// 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_CNT REG_SPI(0, 0x00)
|
#define REG_SPI_BUS0 (0x10160800)
|
||||||
#define REG_SPI_DONE REG_SPI(0, 0x04)
|
#define REG_SPI_BUS1 (0x10142800)
|
||||||
#define REG_SPI_BLKLEN REG_SPI(0, 0x08)
|
#define REG_SPI_BUS2 (0x10143800)
|
||||||
#define REG_SPI_FIFO REG_SPI(0, 0x0C)
|
|
||||||
#define REG_SPI_STATUS REG_SPI(0, 0x10)
|
|
||||||
|
|
||||||
#define SPI_CNT_BUSY BIT(15)
|
#define REG_SPI_CONTROL 0x00
|
||||||
#define SPI_CNT_START BIT(15)
|
#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_CONTROL_RATE(n) (n)
|
||||||
#define SPI_CNT_WRITE BIT(13)
|
#define SPI_CONTROL_CS(n) ((n) << 6)
|
||||||
|
#define SPI_DIRECTION_READ (0)
|
||||||
#define SPI_CNT_RATE(n) (n)
|
#define SPI_DIRECTION_WRITE BIT(13)
|
||||||
#define SPI_CNT_CS(n) ((n) << 6)
|
#define SPI_CONTROL_BUSY BIT(15)
|
||||||
|
#define SPI_CONTROL_START BIT(15)
|
||||||
|
|
||||||
#define SPI_STAT_BUSY BIT(0)
|
#define SPI_STAT_BUSY BIT(0)
|
||||||
|
|
||||||
#define SPI_FIFO_WIDTH (32)
|
#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 };
|
while(REG_SPI(bus, REG_SPI_CONTROL) & SPI_CONTROL_BUSY);
|
||||||
if (dev < countof(SPI_DevSelect)) {
|
|
||||||
return SPI_DevSelect[dev];
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static u8 SPI_GetDevBaudrate(u32 dev)
|
static void SPI_WaitFIFO(u32 bus)
|
||||||
{
|
{
|
||||||
static const u8 SPI_BaudRates[] = { 2, 0, 0, 5 };
|
while(REG_SPI(bus, REG_SPI_STAT) & SPI_STAT_BUSY);
|
||||||
if (dev < countof(SPI_BaudRates)) {
|
|
||||||
return SPI_BaudRates[dev];
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
static void SPI_SingleXfer(u32 reg, u32 bus, u32 *buffer, u32 len, bool read)
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
u32 pos = 0;
|
u32 pos = 0;
|
||||||
|
|
||||||
REG_SPI_BLKLEN = len;
|
REG_SPI(bus, REG_SPI_BLKLEN) = len;
|
||||||
REG_SPI_CNT = reg | (read ? SPI_CNT_READ : SPI_CNT_WRITE) | SPI_CNT_START;
|
REG_SPI(bus, REG_SPI_CONTROL) = reg |
|
||||||
|
(read ? SPI_DIRECTION_READ : SPI_DIRECTION_WRITE) | SPI_CONTROL_START;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if ((pos % SPI_FIFO_WIDTH) == 0)
|
if ((pos % SPI_FIFO_WIDTH) == 0)
|
||||||
SPI_WaitFIFO();
|
SPI_WaitFIFO(bus);
|
||||||
|
|
||||||
if (read) {
|
if (read) {
|
||||||
buffer[pos / 4] = REG_SPI_FIFO;
|
buffer[pos / 4] = REG_SPI(bus, REG_SPI_FIFO);
|
||||||
} else {
|
} else {
|
||||||
REG_SPI_FIFO = buffer[pos / 4];
|
REG_SPI(bus, REG_SPI_FIFO) = buffer[pos / 4];
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
int SPI_DoXfer(u32 dev, SPI_XferInfo *xfers, u32 xfer_cnt)
|
||||||
{
|
{
|
||||||
u32 dev_cfg;
|
u32 bus;
|
||||||
int baud, cs;
|
u32 dev_reg;
|
||||||
|
|
||||||
baud = SPI_GetDevBaudrate(dev);
|
bus = SPI_Devices[dev].bus;
|
||||||
cs = SPI_GetDevSelect(dev);
|
dev_reg = SPI_Devices[dev].regcfg;
|
||||||
dev_cfg = SPI_CNT_RATE(baud) | SPI_CNT_CS(cs);
|
|
||||||
|
|
||||||
for (u32 i = 0; i < xfer_cnt; i++) {
|
for (u32 i = 0; i < xfer_cnt; i++) {
|
||||||
SPI_XferInfo *xfer = &xfers[i];
|
SPI_XferInfo *xfer = &xfers[i];
|
||||||
|
|
||||||
SPI_WaitBusy();
|
SPI_WaitBusy(bus);
|
||||||
SPI_SingleXfer(dev_cfg, xfer->read, xfer->buf, xfer->len);
|
SPI_SingleXfer(dev_reg, bus, xfer->buf, xfer->len, xfer->read);
|
||||||
}
|
}
|
||||||
|
|
||||||
SPI_WaitBusy();
|
SPI_WaitBusy(bus);
|
||||||
SPI_Done();
|
SPI_Done(bus);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SPI_Init(void)
|
void SPI_Init(void)
|
||||||
{
|
{
|
||||||
// Hack: here all registers should be set to the "new" mode
|
// This cuts off access from the old SPI
|
||||||
// but GM9 uses the old interface to access NVRAM
|
// interface used during the NDS days
|
||||||
// as such, only the bus used by CODEC will be set to new
|
*REG_CFG_SPI_CNT = 7;
|
||||||
// *CFG_SPI_CNT = 7;
|
|
||||||
*CFG_SPI_CNT = BIT(1);
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user