1
0
Fork 0
forked from len0rd/rockbox
foxbox/firmware/target/arm/pp/uart-pp.c
Solomon Peachy 16a6ad032f 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
2025-08-06 08:27:58 -04:00

270 lines
7.4 KiB
C

/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2002 by Alan Korr & Nick Robinson
*
* 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "button.h"
#include "config.h"
#include "cpu.h"
#include "system.h"
#include "kernel.h"
#include "lcd.h"
#include "serial.h"
#include "iap.h"
#if defined(IPOD_ACCESSORY_PROTOCOL)
struct ppuart {
volatile unsigned long *RBR_THR_DLL;
volatile unsigned long *LCR;
volatile unsigned long *LSR;
int autobaud;
};
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;
*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)
{
int tmp;
#if defined(IPOD_NANO) || defined(IPOD_VIDEO)
/* Route the Tx/Rx pins. 5G Ipods. ser0, dock conncetor */
(*(volatile unsigned long *)(0x7000008C)) &= ~0x0C;
GPO32_ENABLE &= ~0x0C;
DEV_EN = DEV_EN | DEV_SER0;
CPU_HI_INT_DIS = SER0_MASK;
DEV_RS |= DEV_SER0;
sleep(1);
DEV_RS &= ~DEV_SER0;
SER0_LCR = 0x80; /* Divisor latch enable */
SER0_DLM = 0x00;
SER0_LCR = 0x03; /* Divisor latch disable, 8-N-1 */
SER0_IER = 0x01;
SER0_FCR = 0x07; /* Tx+Rx FIFO reset and FIFO enable */
CPU_INT_EN = HI_MASK;
CPU_HI_INT_EN = SER0_MASK;
tmp = SER0_RBR;
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);
DEV_EN |= DEV_SER1;
CPU_HI_INT_DIS = SER1_MASK;
DEV_RS |= DEV_SER1;
sleep(1);
DEV_RS &= ~DEV_SER1;
SER1_LCR = 0x80; /* Divisor latch enable */
SER1_DLM = 0x00;
SER1_LCR = 0x03; /* Divisor latch disable, 8-N-1 */
SER1_IER = 0x01;
SER1_FCR = 0x07; /* Tx+Rx FIFO reset and FIFO enable */
CPU_INT_EN = HI_MASK;
CPU_HI_INT_EN = SER1_MASK;
tmp = SER1_RBR;
/* 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;
DEV_EN |= DEV_SER0;
CPU_HI_INT_DIS = SER0_MASK;
DEV_RS |= DEV_SER0;
sleep(1);
DEV_RS &= ~DEV_SER0;
SER0_LCR = 0x80; /* Divisor latch enable */
SER0_DLM = 0x00;
SER0_LCR = 0x03; /* Divisor latch disable, 8-N-1 */
SER0_IER = 0x01;
SER0_FCR = 0x07; /* Tx+Rx FIFO reset and FIFO enable */
CPU_INT_EN = HI_MASK;
CPU_HI_INT_EN = SER0_MASK;
tmp = SER0_RBR;
SER1.autobaud = 2;
set_bitrate(&SER1, 115200);
SER0.autobaud = 2;
set_bitrate(&SER0, 115200);
#endif
(void)tmp;
}
void serial_bitrate(int rate)
{
if(rate == 0)
{
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
{
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((*SERn->LSR & 0x20))
return 1;
else
return 0;
}
void tx_writec(unsigned char c)
{
*SERn->RBR_THR_DLL = (int)c;
}
void SERIAL_ISR(int port)
{
static int badbaud = 0;
static bool newpkt = true;
char temp;
#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((*SERn->LSR & 0x1))
{
temp = (*SERn->RBR_THR_DLL & 0xFF);
if (newpkt && SERn->autobaud > 0)
{
if (SERn->autobaud == 1)
{
switch (temp)
{
case 0xFF:
case 0x55:
break;
case 0xFC:
set_bitrate(SERn, 19200);
temp = 0xFF;
break;
case 0xE0:
set_bitrate(SERn, 9600);
temp = 0xFF;
break;
default:
badbaud++;
if (badbaud >= 6) /* Switch baud detection mode */
{
SERn->autobaud = 2;
set_bitrate(SERn, 115200);
badbaud = 0;
} else {
set_bitrate(SERn, 57600);
}
continue;
}
} else {
switch (temp)
{
case 0xFF:
case 0x55:
break;
case 0xFE:
set_bitrate(SERn, 57600);
temp = 0xFF;
break;
case 0xFC:
set_bitrate(SERn, 38400);
temp = 0xFF;
break;
case 0xE0:
set_bitrate(SERn, 19200);
temp = 0xFF;
break;
default:
badbaud++;
if (badbaud >= 6) /* Switch baud detection */
{
SERn->autobaud = 1;
set_bitrate(SERn, 57600);
badbaud = 0;
} else {
set_bitrate(SERn, 115200);
}
continue;
}
}
}
bool pkt = iap_getc(temp);
if(newpkt && !pkt)
SERn->autobaud = 0; /* Found good baud */
newpkt = pkt;
}
}
#endif