From 38ae0d53e834e6538e3820c3fd1977c971a81c15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A1stor=20Mu=C3=B1oz?= Date: Sat, 6 Dec 2014 22:33:39 +0100 Subject: [PATCH] iPod Classic: implement HAVE_SERIAL Change-Id: I24a861cd45095d858d1a7db39969f6eda17cc563 --- firmware/SOURCES | 4 + firmware/export/config/ipod6g.h | 2 +- firmware/export/s5l8702.h | 14 ++ firmware/target/arm/s5l8702/debug-s5l8702.c | 42 ++++++ .../target/arm/s5l8702/ipod6g/serial-ipod6g.c | 87 ++++++++++++ firmware/target/arm/s5l8702/system-s5l8702.c | 16 ++- firmware/target/arm/s5l8702/uart-s5l8702.c | 127 ++++++++++++++++++ firmware/target/arm/s5l8702/uart-s5l8702.h | 32 +++++ 8 files changed, 317 insertions(+), 7 deletions(-) create mode 100644 firmware/target/arm/s5l8702/ipod6g/serial-ipod6g.c create mode 100644 firmware/target/arm/s5l8702/uart-s5l8702.c create mode 100644 firmware/target/arm/s5l8702/uart-s5l8702.h diff --git a/firmware/SOURCES b/firmware/SOURCES index 543958ea85..091b3b1da7 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES @@ -1608,7 +1608,11 @@ target/arm/s5l8702/postmortemstub.S target/arm/s5l8702/ipod6g/pmu-ipod6g.c target/arm/s5l8702/ipod6g/rtc-ipod6g.c target/arm/s5l8700/usb-nano2g-6g.c +#ifdef HAVE_SERIAL target/arm/s5l8702/uc8702.c +target/arm/s5l8702/uart-s5l8702.c +target/arm/s5l8702/ipod6g/serial-ipod6g.c +#endif #ifndef BOOTLOADER target/arm/s5l8702/timer-s5l8702.c target/arm/s5l8702/debug-s5l8702.c diff --git a/firmware/export/config/ipod6g.h b/firmware/export/config/ipod6g.h index 3eae08edce..a885a11144 100644 --- a/firmware/export/config/ipod6g.h +++ b/firmware/export/config/ipod6g.h @@ -250,7 +250,7 @@ /* Define this if you can switch on/off the accessory power supply */ #define HAVE_ACCESSORY_SUPPLY //#define IPOD_ACCESSORY_PROTOCOL -//#define HAVE_SERIAL +#define HAVE_SERIAL /* Define this, if you can switch on/off the lineout */ #define HAVE_LINEOUT_POWEROFF diff --git a/firmware/export/s5l8702.h b/firmware/export/s5l8702.h index 34b6da874b..1a59d47036 100644 --- a/firmware/export/s5l8702.h +++ b/firmware/export/s5l8702.h @@ -669,11 +669,18 @@ #define I2SCLKDIV (*((volatile uint32_t*)(0x3CA00040))) +/////UART///// +/* UC8702 uart controller */ +#define S5L8702_UART_BASE 0x3cc00000 +#define S5L8702_UART_PORT_MAX 4 + + /////CLOCK GATES///// #define CLOCKGATE_USB_1 2 #define CLOCKGATE_USB_2 35 #define CLOCKGATE_DMAC0 25 #define CLOCKGATE_DMAC1 26 +#define CLOCKGATE_UART 41 /////INTERRUPTS///// @@ -687,6 +694,13 @@ #define IRQ_ATA 29 #define IRQ_MMC 44 +#define IRQ_UART(i) (24+i) +#define IRQ_UART0 24 +#define IRQ_UART1 25 +#define IRQ_UART2 26 +#define IRQ_UART3 27 +#define IRQ_UART4 28 /* obsolete/not implemented on s5l8702 ??? */ + #define IRQ_EXT0 0 #define IRQ_EXT1 1 #define IRQ_EXT2 2 diff --git a/firmware/target/arm/s5l8702/debug-s5l8702.c b/firmware/target/arm/s5l8702/debug-s5l8702.c index c49737756c..a2c6c0b193 100644 --- a/firmware/target/arm/s5l8702/debug-s5l8702.c +++ b/firmware/target/arm/s5l8702/debug-s5l8702.c @@ -30,6 +30,9 @@ #include "power.h" #include "pmu-target.h" #include "pcm-target.h" +#ifdef HAVE_SERIAL +#include "uc8702.h" +#endif #define DEBUG_CANCEL BUTTON_MENU @@ -46,7 +49,11 @@ bool dbg_hw_info(void) int line; int i; unsigned int state = 0; +#ifdef UC8702_DEBUG + const unsigned int max_states=3; +#else const unsigned int max_states=2; +#endif lcd_clear_display(); lcd_setfont(FONT_SYSFIXED); @@ -100,6 +107,41 @@ bool dbg_hw_info(void) _DEBUG_PRINTF("backlight: %s", pmu_read(0x29) ? "on" : "off"); _DEBUG_PRINTF("brightness value: %d", pmu_read(0x28)); } +#ifdef UC8702_DEBUG + else if(state==2) + { + extern struct uartc_port ser_port; + int tx_stat, rx_stat, tx_speed, rx_speed; + char line_cfg[4]; + int abr_stat; + unsigned int abr_cnt; + + char *abrstatus[] = {"Idle", "Launched", "Counting", "Abnormal"}; + + uartc_port_get_line_info(&ser_port, &tx_stat, &rx_stat, + &tx_speed, &rx_speed, line_cfg); + + abr_stat = uartc_port_get_abr_info(&ser_port, &abr_cnt); + + _DEBUG_PRINTF("UART %d:", ser_port.id); + line++; + _DEBUG_PRINTF("line: %s", line_cfg); + _DEBUG_PRINTF("Tx: %s, speed: %d", tx_stat ? "On":"Off", tx_speed); + _DEBUG_PRINTF("Rx: %s, speed: %d", rx_stat ? "On":"Off", rx_speed); + _DEBUG_PRINTF("ABR: %s, cnt: %d", abrstatus[abr_stat], abr_cnt); + line++; + _DEBUG_PRINTF("n_tx_bytes: %u", ser_port.n_tx_bytes); + _DEBUG_PRINTF("n_rx_bytes: %u", ser_port.n_rx_bytes); + _DEBUG_PRINTF("n_ovr_err: %u", ser_port.n_ovr_err); + _DEBUG_PRINTF("n_parity_err: %u", ser_port.n_parity_err); + _DEBUG_PRINTF("n_frame_err: %u", ser_port.n_frame_err); + _DEBUG_PRINTF("n_break_detect: %u", ser_port.n_break_detect); + _DEBUG_PRINTF("n_abnormal0: %u", ser_port.n_abnormal0); + _DEBUG_PRINTF("n_abnormal1: %u", ser_port.n_abnormal1); + + sleep(HZ/20); + } +#endif else { state=0; diff --git a/firmware/target/arm/s5l8702/ipod6g/serial-ipod6g.c b/firmware/target/arm/s5l8702/ipod6g/serial-ipod6g.c new file mode 100644 index 0000000000..c03ba9bc24 --- /dev/null +++ b/firmware/target/arm/s5l8702/ipod6g/serial-ipod6g.c @@ -0,0 +1,87 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2014 by Cástor Muñoz + * + * 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 +#include +#include + +#include "config.h" +#include "cpu.h" +#include "system.h" +#include "kernel.h" + +#include "serial.h" +#include "s5l8702.h" +#include "uc8702.h" +#include "uart-s5l8702.h" + +/* Define LOGF_ENABLE to enable logf output in this file */ +#define LOGF_ENABLE +#include "logf.h" + + +/* shall include serial HW configuracion for specific target */ +#define IPOD6G_UART_CLK_HZ 12000000 /* external OSC0 ??? */ + +extern struct uartc s5l8702_uart; + +struct uartc_port ser_port IDATA_ATTR = { + /* location */ + .uartc = &s5l8702_uart, + .id = 0, + + /* configuration */ + .rx_trg = UFCON_RX_FIFO_TRG_4, + .tx_trg = UFCON_TX_FIFO_TRG_EMPTY, + .clksel = UCON_CLKSEL_ECLK, + .clkhz = IPOD6G_UART_CLK_HZ, + + /* interrupt callbacks */ + .rx_cb = NULL, + .tx_cb = NULL, /* polling */ +}; + +/* + * serial driver API + */ +void serial_setup(void) +{ + uart_port_init(&ser_port); + + /* set a default configuration, Tx and Rx modes are + disabled when the port is initialized */ + uartc_port_config(&ser_port, 115200, ULCON_DATA_BITS_8, + ULCON_PARITY_NONE, ULCON_STOP_BITS_1); + + /* enable Tx interrupt request or POLLING mode */ + uartc_port_set_tx_mode(&ser_port, UCON_MODE_INTREQ); + + logf("[%lu] serial_setup(): port %d ready!", USEC_TIMER, ser_port.id); +} + +int tx_rdy(void) +{ + return uartc_port_tx_ready(&ser_port) ? 1 : 0; +} + +void tx_writec(unsigned char c) +{ + uartc_port_tx_byte(&ser_port, c); +} diff --git a/firmware/target/arm/s5l8702/system-s5l8702.c b/firmware/target/arm/s5l8702/system-s5l8702.c index a9db7e1b8d..014ed910de 100644 --- a/firmware/target/arm/s5l8702/system-s5l8702.c +++ b/firmware/target/arm/s5l8702/system-s5l8702.c @@ -26,6 +26,7 @@ #include "pmu-target.h" #include "gpio-s5l8702.h" #include "dma-s5l8702.h" +#include "uart-s5l8702.h" #define default_interrupt(name) \ extern __attribute__((weak,alias("UIRQ"))) void name (void) @@ -64,11 +65,11 @@ default_interrupt(INT_IRQ20); default_interrupt(INT_IRQ21); default_interrupt(INT_IRQ22); default_interrupt(INT_WHEEL); -default_interrupt(INT_IRQ24); -default_interrupt(INT_IRQ25); -default_interrupt(INT_IRQ26); -default_interrupt(INT_IRQ27); -default_interrupt(INT_IRQ28); +default_interrupt(INT_UART0); +default_interrupt(INT_UART1); +default_interrupt(INT_UART2); +default_interrupt(INT_UART3); +default_interrupt(INT_IRQ28); /* obsolete/not implemented UART4 ??? */ default_interrupt(INT_ATA); default_interrupt(INT_IRQ30); default_interrupt(INT_EXT4); /* GPIOIC group 2 (not used) */ @@ -133,7 +134,7 @@ static void (* const irqvector[])(void) = INT_EXT0,INT_EXT1,INT_EXT2,INT_EXT3,INT_IRQ4,INT_IRQ5,INT_IRQ6,INT_TIMER32, INT_TIMER,INT_IRQ9,INT_IRQ10,INT_IRQ11,INT_IRQ12,INT_IRQ13,INT_IRQ14,INT_IRQ15, INT_DMAC0,INT_DMAC1,INT_IRQ18,INT_USB_FUNC,INT_IRQ20,INT_IRQ21,INT_IRQ22,INT_WHEEL, - INT_IRQ24,INT_IRQ25,INT_IRQ26,INT_IRQ27,INT_IRQ28,INT_ATA,INT_IRQ30,INT_EXT4, + INT_UART0,INT_UART1,INT_UART2,INT_UART3,INT_IRQ28,INT_ATA,INT_IRQ30,INT_EXT4, INT_EXT5,INT_EXT6,INT_IRQ34,INT_IRQ35,INT_IRQ36,INT_IRQ37,INT_IRQ38,INT_IRQ39, INT_IRQ40,INT_IRQ41,INT_IRQ42,INT_IRQ43,INT_MMC,INT_IRQ45,INT_IRQ46,INT_IRQ47, INT_IRQ48,INT_IRQ49,INT_IRQ50,INT_IRQ51,INT_IRQ52,INT_IRQ53,INT_IRQ54,INT_IRQ55, @@ -185,6 +186,9 @@ void system_init(void) gpio_init(); pmu_init(); dma_init(); +#ifdef HAVE_SERIAL + uart_init(); +#endif VIC0INTENABLE = 1 << IRQ_WHEEL; VIC0INTENABLE = 1 << IRQ_ATA; VIC1INTENABLE = 1 << (IRQ_MMC - 32); diff --git a/firmware/target/arm/s5l8702/uart-s5l8702.c b/firmware/target/arm/s5l8702/uart-s5l8702.c new file mode 100644 index 0000000000..45d61ba627 --- /dev/null +++ b/firmware/target/arm/s5l8702/uart-s5l8702.c @@ -0,0 +1,127 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2014 by Cástor Muñoz + * + * 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 Standard files */ +#include +#include +#include + +#include "config.h" +#include "cpu.h" +#include "system.h" +#include "kernel.h" + +#include "s5l8702.h" +#include "uc8702.h" +#include "uart-s5l8702.h" + + +/* s5l8702 UART configuration */ +struct uartc s5l8702_uart = { + .baddr = S5L8702_UART_BASE +}; + +/* + * Device level functions specific to S5L8702 + */ +void uart_gpio_control(int port_id, bool onoff) +{ + if (onoff) { + switch (port_id) { + case 0: + /* configure UART0 Tx/Rx GPIO ports */ + PCON0 = (PCON0 & 0xff00ffff) | 0x00220000; + break; + case 1: + /* configure UART1 GPIO ports, including RTS/CTS signals */ + PCOND = (PCOND & 0xff0000ff) | 0x00222200; + break; + case 2: + case 3: + /* unknown, probably UART3/4 not routed on s5l8702 */ + default: + break; + } + } + else { + /* configure minimal power consumption */ + switch (port_id) { + case 0: + PCON0 = (PCON0 & 0xff00ffff) | 0x00ee0000; + break; + case 1: + PCOND = (PCOND & 0xff0000ff) | 0x00eeee00; + break; + case 2: + case 3: + default: + break; + } + } +} + +/* reset s5l8702 uart related hardware */ +static void s5l8702_uart_hw_init(void) +{ + for (int id = 0; id < S5L8702_UART_PORT_MAX; id++) { + VIC0INTENCLEAR = 1 << IRQ_UART(id); /* mask INT */ + uart_gpio_control(id, 0); + } +} + +void uart_init(void) +{ + s5l8702_uart_hw_init(); + PWRCON(1) &= ~(1 << (CLOCKGATE_UART - 32)); /* on */ + uartc_open(&s5l8702_uart); +} + +void uart_close(void) +{ + uartc_close(&s5l8702_uart); + PWRCON(1) |= (1 << (CLOCKGATE_UART - 32)); /* off */ + s5l8702_uart_hw_init(); +} + +void uart_port_init(struct uartc_port *port) +{ + uart_gpio_control(port->id, 1); + uartc_port_open(port); + VIC0INTENABLE = 1 << IRQ_UART(port->id); /* unmask INT */ +} + +void uart_port_close(struct uartc_port *port) +{ + VIC0INTENCLEAR = 1 << IRQ_UART(port->id); /* mask INT */ + uartc_port_close(port); + uart_gpio_control(port->id, 0); +} + +/* ISRs */ +void ICODE_ATTR INT_UART0(void) +{ + uartc_callback(&s5l8702_uart, 0); +} + +void ICODE_ATTR INT_UART1(void) +{ + uartc_callback(&s5l8702_uart, 1); +} diff --git a/firmware/target/arm/s5l8702/uart-s5l8702.h b/firmware/target/arm/s5l8702/uart-s5l8702.h new file mode 100644 index 0000000000..c7ec684284 --- /dev/null +++ b/firmware/target/arm/s5l8702/uart-s5l8702.h @@ -0,0 +1,32 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2014 by Cástor Muñoz + * + * 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. + * + ****************************************************************************/ +#ifndef __UART_S5L8702_H__ +#define __UART_S5L8702_H__ + +#include "uc8702.h" + +/* s5l8702 low level routines */ +void uart_init (void); +void uart_close(void); +void uart_port_init (struct uartc_port *port); +void uart_port_close (struct uartc_port *port); + +#endif /* __UART_S5L8702_H__ */