pp502x: Restructure UART code

* Move to a structure instead of pointers to registers
 * Autobaud operates per-uart
 * When explitily setting uart speed, it applies to all uarts

This allows both UARTs to be enabled and serviced simultaneously,
allowing either accessory port to be used.  Note that the last
port to receive something is where subsequent transmits are directed,
and only one set of IAP state is maintained.

To change this, we will need to revamp IAP to support more than
one state machine, and then extend the serial API to allow for both
UARTs to be used independently.  Probably not worth the effort.

Change-Id: I0142f0906706fc0c4ee6d6d7aa6b0515e1a749dd
This commit is contained in:
Solomon Peachy 2025-07-29 12:16:38 -04:00
parent 921abc7beb
commit 16a6ad032f
2 changed files with 65 additions and 76 deletions

View file

@ -190,9 +190,11 @@ void __attribute__((interrupt("IRQ"))) irq_handler(void)
else if (CPU_HI_INT_STAT & SER0_MASK) {
SERIAL_ISR(0);
}
#if defined(IPOD_COLOR) || defined(IPOD_4G) || defined(IPOD_MINI) || defined(IPOD_MINI2G)
else if (CPU_HI_INT_STAT & SER1_MASK) {
SERIAL_ISR(1);
}
#endif
#endif
} else {
if (COP_INT_STAT & TIMER2_MASK)

View file

@ -31,17 +31,29 @@
#include "iap.h"
#if defined(IPOD_ACCESSORY_PROTOCOL)
static int autobaud = 0;
volatile unsigned long * base_RBR, * base_THR, * base_LCR, * base_LSR, * base_DLL;
struct ppuart {
volatile unsigned long *RBR_THR_DLL;
volatile unsigned long *LCR;
volatile unsigned long *LSR;
int autobaud;
};
static void set_bitrate(unsigned int rate)
static struct ppuart SER0 = { &SER0_RBR, &SER0_LCR, &SER0_LSR, 0 };
#if defined(IPOD_COLOR) || defined(IPOD_4G) || defined(IPOD_MINI) || defined(IPOD_MINI2G)
static struct ppuart SER1 = { &SER1_RBR, &SER1_LCR, &SER1_LSR, 0 };
static volatile struct ppuart *SERn = &SER1; // ie dock connector
#else
static volatile struct ppuart *SERn = &SER0;
#endif
static void set_bitrate(volatile struct ppuart *port, unsigned int rate)
{
unsigned int divisor;
divisor = 24000000L / rate / 16;
*base_LCR = 0x80; /* Divisor latch enable */
*base_DLL = (divisor >> 0) & 0xFF;
*base_LCR = 0x03; /* Divisor latch disable, 8-N-1 */
*port->LCR = 0x80; /* Divisor latch enable */
*port->RBR_THR_DLL = (divisor >> 0) & 0xFF;
*port->LCR = 0x03; /* Divisor latch disable, 8-N-1 */
}
void serial_setup (void)
@ -53,12 +65,6 @@ void serial_setup (void)
(*(volatile unsigned long *)(0x7000008C)) &= ~0x0C;
GPO32_ENABLE &= ~0x0C;
base_RBR = &SER0_RBR;
base_THR = &SER0_THR;
base_LCR = &SER0_LCR;
base_LSR = &SER0_LSR;
base_DLL = &SER0_DLL;
DEV_EN = DEV_EN | DEV_SER0;
CPU_HI_INT_DIS = SER0_MASK;
@ -77,22 +83,18 @@ void serial_setup (void)
CPU_HI_INT_EN = SER0_MASK;
tmp = SER0_RBR;
serial_bitrate(0);
SER0.autobaud = 2;
set_bitrate(&SER0, 115200);
#elif defined(IPOD_COLOR) || defined(IPOD_4G) || defined(IPOD_MINI) || defined(IPOD_MINI2G)
/* Route the Tx/Rx pins. 4G Ipods, MINI & MINI2G. ser1, dock connector */
GPIO_CLEAR_BITWISE(GPIOD_ENABLE, 0x6);
GPIO_CLEAR_BITWISE(GPIOD_OUTPUT_EN, 0x6);
GPIOD_INT_CLR = 0x6;
outl(0x70000018, inl(0x70000018) & ~0xc00);
base_RBR = &SER1_RBR;
base_THR = &SER1_THR;
base_LCR = &SER1_LCR;
base_LSR = &SER1_LSR;
base_DLL = &SER1_DLL;
DEV_EN |= DEV_SER1;
CPU_HI_INT_DIS = SER1_MASK;
@ -111,19 +113,11 @@ void serial_setup (void)
CPU_HI_INT_EN = SER1_MASK;
tmp = SER1_RBR;
serial_bitrate(0);
/* Route the Tx/Rx pins. 4G Ipod, ser0, top connector */
GPIO_CLEAR_BITWISE(GPIOC_INT_EN, 0x8);
GPIO_CLEAR_BITWISE(GPIOC_INT_LEV, 0x8);
GPIOC_INT_CLR = 0x8;
base_RBR = &SER0_RBR;
base_THR = &SER0_THR;
base_LCR = &SER0_LCR;
base_LSR = &SER0_LSR;
base_DLL = &SER0_DLL;
DEV_EN |= DEV_SER0;
CPU_HI_INT_DIS = SER0_MASK;
@ -142,7 +136,10 @@ void serial_setup (void)
CPU_HI_INT_EN = SER0_MASK;
tmp = SER0_RBR;
serial_bitrate(0);
SER1.autobaud = 2;
set_bitrate(&SER1, 115200);
SER0.autobaud = 2;
set_bitrate(&SER0, 115200);
#endif
@ -154,27 +151,27 @@ void serial_bitrate(int rate)
{
if(rate == 0)
{
autobaud = 2;
set_bitrate(115200);
SER0.autobaud = 2;
set_bitrate(&SER0, 115200);
#if defined(IPOD_COLOR) || defined(IPOD_4G) || defined(IPOD_MINI) || defined(IPOD_MINI2G)
SER1.autobaud = 2;
set_bitrate(&SER1, 115200);
#endif
}
else
{
autobaud = 0;
set_bitrate(rate);
SER0.autobaud = 0;
set_bitrate(&SER0, rate);
#if defined(IPOD_COLOR) || defined(IPOD_4G) || defined(IPOD_MINI) || defined(IPOD_MINI2G)
SER1.autobaud = 0;
set_bitrate(&SER1, rate);
#endif
}
}
int tx_rdy(void)
{
if((*base_LSR & 0x20))
return 1;
else
return 0;
}
static int rx_rdy(void)
{
if((*base_LSR & 0x1))
if((*SERn->LSR & 0x20))
return 1;
else
return 0;
@ -182,12 +179,7 @@ static int rx_rdy(void)
void tx_writec(unsigned char c)
{
*base_THR =(int) c;
}
static unsigned char rx_readc(void)
{
return (*base_RBR & 0xFF);
*SERn->RBR_THR_DLL = (int)c;
}
void SERIAL_ISR(int port)
@ -196,26 +188,21 @@ void SERIAL_ISR(int port)
static bool newpkt = true;
char temp;
if (port && base_RBR != &SER1_RBR) {
base_RBR = &SER1_RBR;
base_THR = &SER1_THR;
base_LCR = &SER1_LCR;
base_LSR = &SER1_LSR;
base_DLL = &SER1_DLL;
} else if (!port && base_RBR != &SER0_RBR) {
base_RBR = &SER0_RBR;
base_THR = &SER0_THR;
base_LCR = &SER0_LCR;
base_LSR = &SER0_LSR;
base_DLL = &SER0_DLL;
}
#if defined(IPOD_COLOR) || defined(IPOD_4G) || defined(IPOD_MINI) || defined(IPOD_MINI2G)
if (port && SERn != &SER1)
SERn = &SER1;
else if (!port && SERn != &SER0)
SERn = &SER0;
#else
(void)port;
#endif
while(rx_rdy())
while((*SERn->LSR & 0x1))
{
temp = rx_readc();
if (newpkt && autobaud > 0)
temp = (*SERn->RBR_THR_DLL & 0xFF);
if (newpkt && SERn->autobaud > 0)
{
if (autobaud == 1)
if (SERn->autobaud == 1)
{
switch (temp)
{
@ -223,22 +210,22 @@ void SERIAL_ISR(int port)
case 0x55:
break;
case 0xFC:
set_bitrate(19200);
set_bitrate(SERn, 19200);
temp = 0xFF;
break;
case 0xE0:
set_bitrate(9600);
set_bitrate(SERn, 9600);
temp = 0xFF;
break;
default:
badbaud++;
if (badbaud >= 6) /* Switch baud detection mode */
{
autobaud = 2;
set_bitrate(115200);
SERn->autobaud = 2;
set_bitrate(SERn, 115200);
badbaud = 0;
} else {
set_bitrate(57600);
set_bitrate(SERn, 57600);
}
continue;
}
@ -249,26 +236,26 @@ void SERIAL_ISR(int port)
case 0x55:
break;
case 0xFE:
set_bitrate(57600);
set_bitrate(SERn, 57600);
temp = 0xFF;
break;
case 0xFC:
set_bitrate(38400);
set_bitrate(SERn, 38400);
temp = 0xFF;
break;
case 0xE0:
set_bitrate(19200);
set_bitrate(SERn, 19200);
temp = 0xFF;
break;
default:
badbaud++;
if (badbaud >= 6) /* Switch baud detection */
{
autobaud = 1;
set_bitrate(57600);
SERn->autobaud = 1;
set_bitrate(SERn, 57600);
badbaud = 0;
} else {
set_bitrate(115200);
set_bitrate(SERn, 115200);
}
continue;
}
@ -276,7 +263,7 @@ void SERIAL_ISR(int port)
}
bool pkt = iap_getc(temp);
if(newpkt && !pkt)
autobaud = 0; /* Found good baud */
SERn->autobaud = 0; /* Found good baud */
newpkt = pkt;
}
}