diff options
author | Vencislav Atanasov <user890104@freemyipod.org> | 2024-12-06 23:37:49 +0200 |
---|---|---|
committer | Vencislav Atanasov <user890104@freemyipod.org> | 2024-12-06 23:59:27 +0200 |
commit | 2669548bcd68ff635f74493782c080d3c735194b (patch) | |
tree | d6c934d88693c01d025a212cbebbc99ed3618107 | |
parent | b240f01059386e883949de558e2cbdf14de887fc (diff) | |
download | rockbox-2669548bcd.tar.gz rockbox-2669548bcd.zip |
S5L8720: Add support for Timers, SPI, CPUFREQ and USB
This also includes a small SPI driver rework for ipod6g. Only the NOR flash currently uses SPI. Tested on target using View SysCfg in Debug menu.
This is a part of the large iPod Nano 4G and iPod Touch 2G support patch.
Credit: Cástor Muñoz <cmvidal@gmail.com>
Change-Id: If2b91c1088034dd606abc6dd0b6ad73dea0152a4
-rw-r--r-- | firmware/target/arm/s5l8702/kernel-s5l8702.c | 16 | ||||
-rw-r--r-- | firmware/target/arm/s5l8702/spi-s5l8702.c | 50 | ||||
-rw-r--r-- | firmware/target/arm/s5l8702/system-target.h | 7 | ||||
-rw-r--r-- | firmware/target/arm/s5l8702/usb-s5l8702.c | 6 |
4 files changed, 76 insertions, 3 deletions
diff --git a/firmware/target/arm/s5l8702/kernel-s5l8702.c b/firmware/target/arm/s5l8702/kernel-s5l8702.c index 6a70981c93..0a5413af73 100644 --- a/firmware/target/arm/s5l8702/kernel-s5l8702.c +++ b/firmware/target/arm/s5l8702/kernel-s5l8702.c @@ -7,7 +7,7 @@ * \/ \/ \/ \/ \/ * $Id: kernel-s5l8700.c 28795 2010-12-11 17:52:52Z Buschel $ * - * Copyright © 2009 Bertrik Sikken + * Copyright © 2009 Bertrik Sikken * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -39,6 +39,7 @@ void tick_start(unsigned int interval_in_ms) { int cycles = 10 * interval_in_ms; +#if CONFIG_CPU == S5L8702 /* configure timer for 10 kHz (12 MHz / 16 / 75) */ TBCMD = (1 << 1); /* TB_CLR */ TBPRE = 75 - 1; /* prescaler */ @@ -50,5 +51,18 @@ void tick_start(unsigned int interval_in_ms) (0 << 4); /* TB_MODE_SEL = interval mode */ TBDATA0 = cycles; /* set interval period */ TBCMD = (1 << 0); /* TB_EN */ +#elif CONFIG_CPU == S5L8720 + /* configure timer for 10 kHz (24 MHz / 16 / 150) */ + TBCMD = (1 << 1); /* TB_CLR */ + TBPRE = 150 - 1; /* prescaler */ + TBCON = (0 << 13) | /* TB_INT1_EN */ + (1 << 12) | /* TB_INT0_EN */ + (0 << 11) | /* TB_START */ + (2 << 8) | /* TB_CS = ECLK / 16 */ + (1 << 6) | /* select ECLK (24 MHz) */ + (0 << 4); /* TB_MODE_SEL = interval mode */ + TBDATA0 = cycles; /* set interval period */ + TBCMD = (1 << 0); /* TB_EN */ +#endif } diff --git a/firmware/target/arm/s5l8702/spi-s5l8702.c b/firmware/target/arm/s5l8702/spi-s5l8702.c index 4c0a409c67..5178da0342 100644 --- a/firmware/target/arm/s5l8702/spi-s5l8702.c +++ b/firmware/target/arm/s5l8702/spi-s5l8702.c @@ -47,6 +47,7 @@ void spi_init(int port, bool state) case 0: PCON0 = (PCON0 & ~0xffff) | val; break; +#if CONFIG_CPU == S5L8702 case 1: PCON6 = (PCON6 & ~0xffff0000) | (val << 16); break; @@ -54,6 +55,15 @@ void spi_init(int port, bool state) PCON14 = (PCON14 & ~0xff000000) | (val << 24); PCON15 = (PCON15 & ~0xff) | (val >> 8); break; +#elif CONFIG_CPU == S5L8720 + case 1: + PCON4 = (PCON4 & ~0xff000000) | (val << 24); + PCON5 = (PCON5 & ~0xff) | (val >> 8); + break; + case 2: + /* unknown */ + break; +#endif } } @@ -67,19 +77,33 @@ void spi_ce(int port, bool state) switch (port) { case 0: GPIOCMD = 0x0000e | level; break; +#if CONFIG_CPU == S5L8702 case 1: GPIOCMD = 0x6040e | level; break; case 2: GPIOCMD = 0xe060e | level; break; +#elif CONFIG_CPU == S5L8720 + case 1: GPIOCMD = 0x4060e | level; break; + case 2: /* unknown */ break; +#endif } } void spi_prepare(int port) { clockgate_enable(SPICLKGATE(port), true); +#if CONFIG_CPU == S5L8720 + clockgate_enable(SPICLKGATE_2(port), true); +#endif SPISTATUS(port) = 0xf; SPICTRL(port) |= 0xc; SPICLKDIV(port) = clkdiv[port]; SPIPIN(port) = 6; +#if CONFIG_CPU == S5L8702 SPISETUP(port) = 0x10618; +#elif CONFIG_CPU == S5L8720 + SPIUNK40(port) = 0xffffffff; + SPIUNK3C(port) = 0xffffffff; + SPISETUP(port) = 0x40618; +#endif SPICTRL(port) |= 0xc; SPICTRL(port) = 1; } @@ -87,25 +111,47 @@ void spi_prepare(int port) void spi_release(int port) { clockgate_enable(SPICLKGATE(port), false); +#if CONFIG_CPU == S5L8720 + clockgate_enable(SPICLKGATE_2(port), false); +#endif +} + +static inline void spi_wait_ready(int port) +{ +#if CONFIG_CPU == S5L8702 + while (!(SPISTATUS(port) & 0x3e00)); +#elif CONFIG_CPU == S5L8720 + while (!(SPISTATUS(port) & 0xf800)); +#endif } uint32_t spi_write(int port, uint32_t data) { +#if CONFIG_CPU == S5L8702 SPIRXLIMIT(port) = 1; while ((SPISTATUS(port) & 0x1f0) == 0x100); +#elif CONFIG_CPU == S5L8720 + SPIUNK4C(port) = 1; + SPIRXLIMIT(port) = 1; + // TODO: Wouldn't this be 0x7c0? so that the rule of <<2 is fulfilled in this register? + while ((SPISTATUS(port) & 0x7f0) == 0x400); +#endif SPITXDATA(port) = data; - while (!(SPISTATUS(port) & 0x3e00)); + spi_wait_ready(port); return SPIRXDATA(port); } void spi_read(int port, uint32_t size, void* buf) { uint8_t* buffer = (uint8_t*)buf; +#if CONFIG_CPU == S5L8720 + SPIUNK4C(port) = size; +#endif SPIRXLIMIT(port) = size; SPISETUP(port) |= 1; while (size--) { - while (!(SPISTATUS(port) & 0x3e00)); + spi_wait_ready(port); *buffer++ = SPIRXDATA(port); } SPISETUP(port) &= ~1; diff --git a/firmware/target/arm/s5l8702/system-target.h b/firmware/target/arm/s5l8702/system-target.h index d3db7476ee..65aba53a91 100644 --- a/firmware/target/arm/s5l8702/system-target.h +++ b/firmware/target/arm/s5l8702/system-target.h @@ -25,9 +25,16 @@ #include "mmu-arm.h" #define CPUFREQ_SLEEP 32768 + +#if (CONFIG_CPU == S5L8702) #define CPUFREQ_MAX 216000000 #define CPUFREQ_DEFAULT 54000000 #define CPUFREQ_NORMAL 54000000 +#elif (CONFIG_CPU == S5L8720) +#define CPUFREQ_MAX 266000000 +#define CPUFREQ_DEFAULT 133000000 +#define CPUFREQ_NORMAL 133000000 +#endif #define STORAGE_WANTS_ALIGN diff --git a/firmware/target/arm/s5l8702/usb-s5l8702.c b/firmware/target/arm/s5l8702/usb-s5l8702.c index 9e031a049f..2fa5033ef6 100644 --- a/firmware/target/arm/s5l8702/usb-s5l8702.c +++ b/firmware/target/arm/s5l8702/usb-s5l8702.c @@ -69,10 +69,16 @@ void usb_dw_target_enable_clocks() void usb_dw_target_disable_clocks() { +#if (CONFIG_CPU == S5L8702) OPHYPWR = 0xf; /* PHY: Power down */ udelay(10); ORSTCON = 7; /* PHY: Assert Software Reset */ udelay(10); +#elif (CONFIG_CPU == S5L8720) + OPHYPWR = 0x1f; /* PHY: Power down */ + ORSTCON = 1; /* PHY: Assert Software Reset */ + udelay(1000); +#endif clockgate_enable(CLOCKGATE_USBOTG, false); clockgate_enable(CLOCKGATE_USBPHY, false); |