summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--firmware/SOURCES1
-rw-r--r--firmware/export/s5l8702.h108
-rw-r--r--firmware/target/arm/s5l8702/clocking-s5l8702.c230
-rw-r--r--firmware/target/arm/s5l8702/clocking-s5l8702.h436
-rw-r--r--firmware/target/arm/s5l8702/debug-s5l8702.c31
-rw-r--r--firmware/target/arm/s5l8702/system-s5l8702.c63
-rw-r--r--firmware/target/arm/s5l8702/system-target.h2
7 files changed, 792 insertions, 79 deletions
diff --git a/firmware/SOURCES b/firmware/SOURCES
index 091b3b1da7..cd1bf492d8 100644
--- a/firmware/SOURCES
+++ b/firmware/SOURCES
@@ -1600,6 +1600,7 @@ target/arm/s5l8702/system-s5l8702.c
1600target/arm/s5l8702/gpio-s5l8702.c 1600target/arm/s5l8702/gpio-s5l8702.c
1601target/arm/s5l8702/pl080.c 1601target/arm/s5l8702/pl080.c
1602target/arm/s5l8702/dma-s5l8702.c 1602target/arm/s5l8702/dma-s5l8702.c
1603target/arm/s5l8702/clocking-s5l8702.c
1603target/arm/s5l8702/ipod6g/lcd-ipod6g.c 1604target/arm/s5l8702/ipod6g/lcd-ipod6g.c
1604target/arm/s5l8702/ipod6g/lcd-asm-ipod6g.S 1605target/arm/s5l8702/ipod6g/lcd-asm-ipod6g.S
1605#if 0 //TODO 1606#if 0 //TODO
diff --git a/firmware/export/s5l8702.h b/firmware/export/s5l8702.h
index 1a59d47036..6ec59eaf37 100644
--- a/firmware/export/s5l8702.h
+++ b/firmware/export/s5l8702.h
@@ -39,6 +39,12 @@
39#define TTB_SIZE 0x4000 39#define TTB_SIZE 0x4000
40#define TTB_BASE_ADDR (DRAM_ORIG + DRAM_SIZE - TTB_SIZE) 40#define TTB_BASE_ADDR (DRAM_ORIG + DRAM_SIZE - TTB_SIZE)
41 41
42#define IRAM0_ORIG 0x22000000
43#define IRAM0_SIZE 0x20000
44#define IRAM1_ORIG 0x22020000
45#define IRAM1_SIZE 0x20000
46
47
42/////SYSTEM CONTROLLER///// 48/////SYSTEM CONTROLLER/////
43#define CLKCON0 (*((volatile uint32_t*)(0x3C500000))) 49#define CLKCON0 (*((volatile uint32_t*)(0x3C500000)))
44#define CLKCON1 (*((volatile uint32_t*)(0x3C500004))) 50#define CLKCON1 (*((volatile uint32_t*)(0x3C500004)))
@@ -151,6 +157,9 @@
151 157
152 158
153/////I2C///// 159/////I2C/////
160#define I2CCLKGATE(i) ((i) == 1 ? CLOCKGATE_I2C1 : \
161 CLOCKGATE_I2C0)
162
154#define IICCON(bus) (*((uint32_t volatile*)(0x3C600000 + 0x300000 * (bus)))) 163#define IICCON(bus) (*((uint32_t volatile*)(0x3C600000 + 0x300000 * (bus))))
155#define IICSTAT(bus) (*((uint32_t volatile*)(0x3C600004 + 0x300000 * (bus)))) 164#define IICSTAT(bus) (*((uint32_t volatile*)(0x3C600004 + 0x300000 * (bus))))
156#define IICADD(bus) (*((uint32_t volatile*)(0x3C600008 + 0x300000 * (bus)))) 165#define IICADD(bus) (*((uint32_t volatile*)(0x3C600008 + 0x300000 * (bus))))
@@ -374,9 +383,9 @@
374#define SPIBASE(i) ((i) == 2 ? 0x3d200000 : \ 383#define SPIBASE(i) ((i) == 2 ? 0x3d200000 : \
375 (i) == 1 ? 0x3ce00000 : \ 384 (i) == 1 ? 0x3ce00000 : \
376 0x3c300000) 385 0x3c300000)
377#define SPICLKGATE(i) ((i) == 2 ? 0x2f : \ 386#define SPICLKGATE(i) ((i) == 2 ? CLOCKGATE_SPI2 : \
378 (i) == 1 ? 0x2b : \ 387 (i) == 1 ? CLOCKGATE_SPI1 : \
379 0x22) 388 CLOCKGATE_SPI0)
380#define SPIDMA(i) ((i) == 2 ? 0xd : \ 389#define SPIDMA(i) ((i) == 2 ? 0xd : \
381 (i) == 1 ? 0xf : \ 390 (i) == 1 ? 0xf : \
382 0x5) 391 0x5)
@@ -658,6 +667,10 @@
658 667
659 668
660/////I2S///// 669/////I2S/////
670#define I2SCLKGATE(i) ((i) == 2 ? CLOCKGATE_I2S2 : \
671 (i) == 1 ? CLOCKGATE_I2S1 : \
672 CLOCKGATE_I2S0)
673
661#define I2SCLKCON (*((volatile uint32_t*)(0x3CA00000))) 674#define I2SCLKCON (*((volatile uint32_t*)(0x3CA00000)))
662#define I2STXCON (*((volatile uint32_t*)(0x3CA00004))) 675#define I2STXCON (*((volatile uint32_t*)(0x3CA00004)))
663#define I2STXCOM (*((volatile uint32_t*)(0x3CA00008))) 676#define I2STXCOM (*((volatile uint32_t*)(0x3CA00008)))
@@ -676,38 +689,67 @@
676 689
677 690
678/////CLOCK GATES///// 691/////CLOCK GATES/////
679#define CLOCKGATE_USB_1 2 692#define CLOCKGATE_SHA 0
680#define CLOCKGATE_USB_2 35 693#define CLOCKGATE_LCD 1
681#define CLOCKGATE_DMAC0 25 694#define CLOCKGATE_USBOTG 2
682#define CLOCKGATE_DMAC1 26 695#define CLOCKGATE_SMx 3
683#define CLOCKGATE_UART 41 696#define CLOCKGATE_SM1 4
697#define CLOCKGATE_ATA 5
698#define CLOCKGATE_SDCI 9
699#define CLOCKGATE_AES 10
700#define CLOCKGATE_DMAC0 25
701#define CLOCKGATE_DMAC1 26
702#define CLOCKGATE_ROM 30
703
704#define CLOCKGATE_RTC 32
705#define CLOCKGATE_CWHEEL 33
706#define CLOCKGATE_SPI0 34
707#define CLOCKGATE_USBPHY 35
708#define CLOCKGATE_I2C0 36
709#define CLOCKGATE_TIMER 37
710#define CLOCKGATE_I2C1 38
711#define CLOCKGATE_I2S0 39
712#define CLOCKGATE_UART 41
713#define CLOCKGATE_I2S1 42
714#define CLOCKGATE_SPI1 43
715#define CLOCKGATE_GPIO 44
716#define CLOCKGATE_CHIPID 46
717#define CLOCKGATE_I2S2 47
718#define CLOCKGATE_SPI2 48
684 719
685 720
686/////INTERRUPTS///// 721/////INTERRUPTS/////
687#define IRQ_TIMER32 7 722#define IRQ_TIMER32 7
688#define IRQ_TIMER 8 723#define IRQ_TIMER 8
689#define IRQ_USB_FUNC 19 724#define IRQ_SPI(i) (9+i) /* TBC */
690#define IRQ_DMAC(d) 16 + d 725#define IRQ_SPI0 9
691#define IRQ_DMAC0 16 726#define IRQ_SPI1 10
692#define IRQ_DMAC1 17 727#define IRQ_SPI2 11
693#define IRQ_WHEEL 23 728#define IRQ_LCD 14
694#define IRQ_ATA 29 729#define IRQ_DMAC(d) (16+d)
695#define IRQ_MMC 44 730#define IRQ_DMAC0 16
696 731#define IRQ_DMAC1 17
697#define IRQ_UART(i) (24+i) 732#define IRQ_USB_FUNC 19
698#define IRQ_UART0 24 733#define IRQ_I2C 21 /* TBC */
699#define IRQ_UART1 25 734#define IRQ_WHEEL 23
700#define IRQ_UART2 26 735#define IRQ_UART(i) (24+i)
701#define IRQ_UART3 27 736#define IRQ_UART0 24
702#define IRQ_UART4 28 /* obsolete/not implemented on s5l8702 ??? */ 737#define IRQ_UART1 25
703 738#define IRQ_UART2 26
704#define IRQ_EXT0 0 739#define IRQ_UART3 27
705#define IRQ_EXT1 1 740#define IRQ_UART4 28 /* obsolete/not implemented on s5l8702 ??? */
706#define IRQ_EXT2 2 741#define IRQ_ATA 29
707#define IRQ_EXT3 3 742#define IRQ_SBOOT 36
708#define IRQ_EXT4 31 743#define IRQ_AES 39
709#define IRQ_EXT5 32 744#define IRQ_SHA 40
710#define IRQ_EXT6 33 745#define IRQ_MMC 44
746
747#define IRQ_EXT0 0
748#define IRQ_EXT1 1
749#define IRQ_EXT2 2
750#define IRQ_EXT3 3
751#define IRQ_EXT4 31
752#define IRQ_EXT5 32
753#define IRQ_EXT6 33
711 754
712#endif 755#endif
713
diff --git a/firmware/target/arm/s5l8702/clocking-s5l8702.c b/firmware/target/arm/s5l8702/clocking-s5l8702.c
new file mode 100644
index 0000000000..5293385453
--- /dev/null
+++ b/firmware/target/arm/s5l8702/clocking-s5l8702.c
@@ -0,0 +1,230 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id:
9 *
10 * Copyright (C) 2015 by Cástor Muñoz
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdbool.h>
22
23#include "config.h"
24#include "system.h" /* udelay() */
25#include "s5l8702.h"
26#include "clocking-s5l8702.h"
27
28/* returns configured frequency (PLLxFreq, when locked) */
29unsigned pll_get_cfg_freq(int pll)
30{
31 unsigned pdiv, mdiv, sdiv, f_in;
32 uint32_t pllpms;
33
34 pllpms = PLLPMS(pll);
35
36 pdiv = (pllpms >> PLLPMS_PDIV_POS) & PLLPMS_PDIV_MSK;
37 if (pdiv == 0) return 0;
38 mdiv = (pllpms >> PLLPMS_MDIV_POS) & PLLPMS_MDIV_MSK;
39 sdiv = (pllpms >> PLLPMS_SDIV_POS) & PLLPMS_SDIV_MSK;
40
41 /* experimental results sugests that the HW is working this way */
42 if (mdiv < 2) mdiv += 256;
43
44 if (GET_PMSMOD(pll) == PMSMOD_DIV)
45 {
46 f_in = (GET_DMOSC(pll))
47 ? ((PLLMOD2 & PLLMOD2_ALTOSC_BIT(pll))
48 ? S5L8702_ALTOSC1_HZ
49 : S5L8702_ALTOSC0_HZ)
50 : S5L8702_OSC0_HZ;
51
52 return (f_in * mdiv / pdiv) >> sdiv; /* divide */
53 }
54 else
55 {
56 /* XXX: overflows for high f_in, safe for 32768 Hz */
57 f_in = S5L8702_OSC1_HZ;
58 return (f_in * mdiv * pdiv) >> sdiv; /* multiply */
59 }
60}
61
62/* returns PLLxClk */
63unsigned pll_get_out_freq(int pll)
64{
65 uint32_t pllmode = PLLMODE;
66
67 if ((pllmode & PLLMODE_PLLOUT_BIT(pll)) == 0)
68 return S5L8702_OSC1_HZ; /* slow mode */
69
70 if ((pllmode & PLLMODE_EN_BIT(pll)) == 0)
71 return 0;
72
73 return pll_get_cfg_freq(pll);
74}
75
76/* returns selected oscillator for CG16_SEL_OSC source */
77unsigned soc_get_oscsel_freq(void)
78{
79 return (PLLMODE & PLLMODE_OSCSEL_BIT) ? S5L8702_OSC1_HZ
80 : S5L8702_OSC0_HZ;
81}
82
83/* returns output frequency */
84unsigned cg16_get_freq(volatile uint16_t* cg16)
85{
86 unsigned sel, freq;
87 uint16_t val16 = *cg16;
88
89 if (val16 & CG16_DISABLE_BIT)
90 return 0;
91
92 sel = (val16 >> CG16_SEL_POS) & CG16_SEL_MSK;
93
94 if (val16 & CG16_UNKOSC_BIT)
95 freq = S5L8702_UNKOSC_HZ;
96 else if (sel == CG16_SEL_OSC)
97 freq = soc_get_oscsel_freq();
98 else
99 freq = pll_get_out_freq(--sel);
100
101 freq /= (((val16 >> CG16_DIV1_POS) & CG16_DIV1_MSK) + 1) *
102 (((val16 >> CG16_DIV2_POS) & CG16_DIV2_MSK) + 1);
103
104 return freq;
105}
106
107void soc_set_system_divs(unsigned cdiv, unsigned hdiv, unsigned hprat)
108{
109 uint32_t val = 0;
110 unsigned pdiv = hdiv * hprat;
111
112 if (cdiv > 1)
113 val |= CLKCON1_CDIV_EN_BIT |
114 ((((cdiv >> 1) - 1) & CLKCON1_CDIV_MSK) << CLKCON1_CDIV_POS);
115 if (hdiv > 1)
116 val |= CLKCON1_HDIV_EN_BIT |
117 ((((hdiv >> 1) - 1) & CLKCON1_HDIV_MSK) << CLKCON1_HDIV_POS);
118 if (pdiv > 1)
119 val |= CLKCON1_PDIV_EN_BIT |
120 ((((pdiv >> 1) - 1) & CLKCON1_PDIV_MSK) << CLKCON1_PDIV_POS);
121
122 val |= ((hprat - 1) & CLKCON1_HPRAT_MSK) << CLKCON1_HPRAT_POS;
123
124 CLKCON1 = val;
125
126 while ((CLKCON1 >> 8) != (val >> 8));
127}
128
129unsigned soc_get_system_divs(unsigned *cdiv, unsigned *hdiv, unsigned *pdiv)
130{
131 uint32_t val = CLKCON1;
132
133 if (cdiv)
134 *cdiv = !(val & CLKCON1_CDIV_EN_BIT) ? 1 :
135 (((val >> CLKCON1_CDIV_POS) & CLKCON1_CDIV_MSK) + 1) << 1;
136 if (hdiv)
137 *hdiv = !(val & CLKCON1_HDIV_EN_BIT) ? 1 :
138 (((val >> CLKCON1_HDIV_POS) & CLKCON1_HDIV_MSK) + 1) << 1;
139 if (pdiv)
140 *pdiv = !(val & CLKCON1_PDIV_EN_BIT) ? 1 :
141 (((val >> CLKCON1_PDIV_POS) & CLKCON1_PDIV_MSK) + 1) << 1;
142
143 return cg16_get_freq(&CG16_SYS); /* FClk */
144}
145
146unsigned get_system_freqs(unsigned *cclk, unsigned *hclk, unsigned *pclk)
147{
148 unsigned fclk, cdiv, hdiv, pdiv;
149
150 fclk = soc_get_system_divs(&cdiv, &hdiv, &pdiv);
151
152 if (cclk) *cclk = fclk / cdiv;
153 if (hclk) *hclk = fclk / hdiv;
154 if (pclk) *pclk = fclk / pdiv;
155
156 return fclk;
157}
158
159void soc_set_hsdiv(int hsdiv)
160{
161 SM1_DIV = hsdiv - 1;
162}
163
164int soc_get_hsdiv(void)
165{
166 return (SM1_DIV & 0xf) + 1;
167}
168
169/* each target/app could define its own clk_modes table */
170struct clocking_mode *clk_modes;
171int cur_level = -1;
172
173void clocking_init(struct clocking_mode *modes, int level)
174{
175 /* at this point, CK16_SYS should be already configured
176 and enabled by emCORE/bootloader */
177
178 /* initialize global clocking */
179 clk_modes = modes;
180 cur_level = level;
181
182 /* start initial level */
183 struct clocking_mode *m = clk_modes + cur_level;
184 soc_set_hsdiv(m->hsdiv);
185 soc_set_system_divs(m->cdiv, m->hdiv, m->hprat);
186}
187
188void set_clocking_level(int level)
189{
190 struct clocking_mode *cur, *next;
191
192 int step = (level < cur_level) ? -1 : 1;
193
194 while (cur_level != level)
195 {
196 cur = clk_modes + cur_level;
197 next = cur + step;
198
199 /* step-up */
200 if (next->hsdiv > cur->hsdiv)
201 soc_set_hsdiv(next->hsdiv);
202
203 /* step up/down */
204 soc_set_system_divs(next->cdiv, next->hdiv, next->hprat);
205
206 /* step-down */
207 if (next->hsdiv < cur->hsdiv)
208 soc_set_hsdiv(next->hsdiv);
209
210 cur_level += step;
211 }
212
213 udelay(50); /* TBC: probably not needed */
214}
215
216#if 0
217/* - This function is mainly to documment how s5l8702 ROMBOOT and iPod
218 * Classic diagnostic OF detects primary external clock.
219 * - ATM it is unknown if 24 MHz are used on other targets (i.e. Nano 3G),
220 * other SoC (ROMBOOT identifies itself as s5l8900/s5l8702), a Classic
221 * prototype, or (probably) never used...
222 * - This function should be called only at boot time, GPIO3.5 is also
223 * used for ATA controller.
224 */
225unsigned soc_get_osc0(void)
226{
227 GPIOCMD = 0x30500; /* configure GPIO3.5 as input */
228 return (PDAT3 & 0x20) ? 24000000 : 12000000;
229}
230#endif
diff --git a/firmware/target/arm/s5l8702/clocking-s5l8702.h b/firmware/target/arm/s5l8702/clocking-s5l8702.h
new file mode 100644
index 0000000000..e7e4fab3bd
--- /dev/null
+++ b/firmware/target/arm/s5l8702/clocking-s5l8702.h
@@ -0,0 +1,436 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id:
9 *
10 * Copyright (C) 2015 by Cástor Muñoz
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#ifndef __CLOCKING_S5L8702_H
22#define __CLOCKING_S5L8702_H
23
24/*
25 * - This is work in progress, results are mainly based on experimental
26 * tests using emCORE and/or iPod Classic OF reverse engineering.
27 * - Things marked as TBC are 'somewhat' speculations, so might be
28 * inconplete, inaccurate or erroneous.
29 * - Things not marked as TBC could be also incomplete, inaccurate or
30 * erroneous.
31 */
32
33/* S5L8702 _figured_ clocking:
34 *
35 * CG16_SEL
36 * CG16_UNKOSC_BIT
37 * ||
38 * ||
39 * UNKOSC ||
40 * OSCSEL ------>||
41 * |\ ||
42 * OSC0 -+--------------->| | OSCClk ||
43 * | | |--------------->|| ______
44 * OSC1 -)+-------------->| | || | | FClk
45 * || |/ ||---->| DIV1 |---------------->
46 * || ______ || |______|
47 * || | | Pll0Freq |\ || CG16_SYS
48 * ++===>| PMS0 |--------->| | ||
49 * || |______| | | PLL0Clk || ____________
50 * || PLL0 | |-------->|| | | U2L_Clk
51 * || OSC1 | | ||---->| DIV1,UNK14 |---------->
52 * |+--------------------->| | || |____________|
53 * || |/ || CG16_2L
54 * || PLLOUT0 ||
55 * || || ______
56 * || ______ || | | SVID_Clk
57 * || | | Pll1Freq |\ ||---->| DIV1 |---------------->
58 * ++===>| PMS1 |--------->| | || |______|
59 * | |______| | | PLL1Clk || CG16_SVID (TBC)
60 * | PLL1 | |-------->||
61 * | OSC1 | | || ___________
62 * +--------------------->| | || | | AUDx_Clk
63 * | |/ ||---->| DIV1,DIV2 |----------->
64 * | PLLOUT1 || |___________|
65 * | || CG16_AUDx
66 * | ______ ||
67 * | | | Pll2Freq |\ || ___________
68 * +--->| PMS2 |--------->| | || | | EClk
69 * | |______| | | PLL2Clk ||---->| DIV1,DIV2 |--+-------->
70 * | PLL2 | |-------->|| |___________| |
71 * | OSC1 | | || CG16_RTIME | MIU_Clk
72 * +--------------------->| | || +-------->
73 * |/ || ______
74 * PLLOUT2 || | | U5L_Clk
75 * ||---->| DIV1 |---------------->
76 * || |______|
77 * || CG16_5L
78 *
79 * ______
80 * | | CClk
81 * FClk --+--->| CDIV |------------> ARM_Clk
82 * | |______|
83 * |
84 * | ______
85 * | | | HClk
86 * +--->| HDIV |---------> CLKCON0[31] --> SDR_Clk
87 * | |______| |
88 * | | PWRCON_AHB
89 * | +-----> [0] ----> Clk_SHA1
90 * | [1] ----> Clk_LCD
91 * | [2] ----> Clk_USBOTG
92 * | [3] ----> Clk_SMx TBC: Static Memory
93 * | [4] ----> Clk_SM1 (ctrl) related
94 * | [5] ----> Clk_ATA
95 * | [6] ----> Clk_UNK
96 * | [7] ----> Clk_UNK
97 * | [8] ----> Clk_NAND TBC
98 * | [9] ----> Clk_SDCI
99 * | [10] ---> Clk_AES
100 * | [11] ---> Clk_UNK
101 * | [12] ---> Clk_ECC TBC
102 * | [13] ---> Clk_UNK
103 * | [14] ---> Clk_EV0 TBC: Ext. Video
104 * | [15] ---> Clk_EV1 TBC: Ext. Video
105 * | [16] ---> Clk_EV2 TBC: Ext. Video
106 * | [17] ---> Clk_UNK
107 * | [18] ---> Clk_UNK
108 * | [19] ---> Clk_UNK
109 * | [20] ---> Clk_UNK
110 * | [21] ---> Clk_UNK
111 * | [22] ---> Clk_UNK
112 * | [23] ---> Clk_UNK
113 * | [24] ---> Clk_UNK
114 * | [25] ---> Clk_DMA0
115 * | [26] ---> Clk_DMA1
116 * | [27] ---> Clk_UNK
117 * | [28] ---> Clk_UNK
118 * | [29] ---> Clk_UNK
119 * | [30] ---> Clk_ROM
120 * | [31] ---> Clk_UNK
121 * |
122 * | ______
123 * | | | PClk PWRCON_APB
124 * +--->| PDIV |------------> [0] ----> Clk_RTC
125 * |______| [1] ----> Clk_CWHEEL
126 * [2] ----> Clk_SPI0
127 * [3] ----> Clk_USBPHY
128 * [4] ----> Clk_I2C0
129 * [5] ----> Clk_TIMER 16/32-bit timer
130 * [6] ----> Clk_I2C1
131 * [7] ----> Clk_I2S0
132 * [8] ----> Clk_UNK TBC: SPDIF Out
133 * [9] ----> Clk_UART
134 * [10] ---> Clk_I2S1
135 * [11] ---> Clk_SPI1
136 * [12] ---> Clk_GPIO
137 * [13] ---> Clk_SBOOT TBC: Secure Boot
138 * [14] ---> Clk_CHIPID
139 * [15] ---> Clk_SPI2
140 * [16] ---> Clk_I2S2
141 * [17] ---> Clk_UNK
142 *
143 * IRAM notes:
144 * - IRAM0 (1st. 128 Kb) and IRAM1 (2nd. 128 Kb) uses diferent clocks,
145 * maximum rd/wr speed for IRAM1 is about a half of maximum rd/wr
146 * speed for IRAM0, it is unknown but probably they are different
147 * HW memory.
148 * - masking Clk_SMx disables access to IRAM0 and IRAM1
149 * - masking Clk_SM1 disables access to IRAM1
150 * - IRAM1 rd/wr speed is scaled by SM1_DIV, so it could be related
151 * with Clk_SM1 (TBC)
152 */
153
154#include <inttypes.h>
155#include "config.h"
156
157#define CLOCKING_DEBUG
158
159#if defined(IPOD_6G)
160/* iPod Classic target */
161#define S5L8702_OSC0_HZ 12000000 /* external OSC */
162#define S5L8702_OSC1_HZ 32768 /* from PMU */
163
164#define S5L8702_ALTOSC0_HZ 0 /* TBC */
165#define S5L8702_ALTOSC1_HZ 0 /* TBC */
166
167/* this clock is selected when CG16_UNKOSC_BIT is set,
168 ignoring PLLMODE_CLKSEL and CG16_SEL settings */
169/* TBC: OSC0*2 ???, 24 MHz Xtal ???, USB ??? */
170#define S5L8702_UNKOSC_HZ 24000000
171
172#else
173/* s5l8702 ROMBOOT */
174#define S5L8702_OSC0_HZ (soc_get_osc0()) /* external OSC */
175#define S5L8702_OSC1_HZ 32768 /* from PMU */
176
177#define S5L8702_ALTOSC0_HZ 1800000
178#define S5L8702_ALTOSC1_HZ 27000000
179#endif
180
181/* TODO: join all these definitions in an unique place */
182#if 1
183#include "s5l8702.h"
184#else
185#define CLKCON0 (*((volatile uint32_t*)(0x3C500000)))
186#define CLKCON1 (*((volatile uint32_t*)(0x3C500004)))
187#define CLKCON2 (*((volatile uint32_t*)(0x3C500008)))
188#define CLKCON3 (*((volatile uint32_t*)(0x3C50000C)))
189#define CLKCON4 (*((volatile uint32_t*)(0x3C500010)))
190#define CLKCON5 (*((volatile uint32_t*)(0x3C500014)))
191#define PLL0PMS (*((volatile uint32_t*)(0x3C500020)))
192#define PLL1PMS (*((volatile uint32_t*)(0x3C500024)))
193#define PLL2PMS (*((volatile uint32_t*)(0x3C500028)))
194#define PLL0LCNT (*((volatile uint32_t*)(0x3C500030)))
195#define PLL1LCNT (*((volatile uint32_t*)(0x3C500034)))
196#define PLL2LCNT (*((volatile uint32_t*)(0x3C500038)))
197#define PLLLOCK (*((volatile uint32_t*)(0x3C500040)))
198#define PLLMODE (*((volatile uint32_t*)(0x3C500044)))
199#define PWRCON(i) (*((volatile uint32_t*)(0x3C500048 + ((i)*4)))) /*i=1,2*/
200#endif
201
202/* TBC: ATM i am assuming that PWRCON_AHB/APB registers are clockgates
203 * for SoC internal controllers sitting on AHB/APB buses, this is based
204 * on other similar SoC documentation and experimental results for many
205 * (not all) s5l8702 controllers.
206 */
207#define PWRCON_AHB (*((uint32_t volatile*)(0x3C500048)))
208#define PWRCON_APB (*((uint32_t volatile*)(0x3C50004c)))
209
210#define PLLPMS(i) (*((volatile uint32_t*)(0x3C500020 + ((i) * 4))))
211#define PLLCNT(i) (*((volatile uint32_t*)(0x3C500030 + ((i) * 4))))
212#define PLLMOD2 (*((volatile uint32_t*)(0x3C500060)))
213#define PLLCNT_MSK 0x3fffff
214
215/* TBC: Clk_SM1 = HClk / (SM1_DIV[3:0] + 1) */
216#define SM1_DIV (*((volatile uint32_t*)(0x38501000)))
217
218
219/* CG16_x: for readability and debug, these gates are defined as
220 * 16-bit registers, on HW they are really halves of 32-bit registers.
221 * Some functionallity is not available on all CG16 gates (when so,
222 * related bits are read-only and fixed to 0).
223 *
224 * CLKCONx DIV1 DIV2 UNKOSC UNK14
225 * CG16_SYS 0L +
226 * CG16_2L 2L + +(TBC) +(TBC)
227 * CG16_SVID 2H + +(TBC)
228 * CG16_AUD0 3L + +
229 * CG16_AUD1 3H + +
230 * CG16_AUD2 4L + +
231 * CG16_RTIME 4H + + +
232 * CG16_5L 5L +
233 *
234 * Not all gates are fully tested, this information is mainly based
235 * on experimental test using emCORE:
236 * - CG16_SYS and CG16_RTIME were tested mainly using time benchs.
237 * - EClk is used as a fixed clock (not depending on CPU/AHB/APB
238 * settings) for the timer contrller. MIU_Clk is used by the MIU
239 * controller to generate the DRAM refresh signals.
240 * - AUDxClk are a source selection for I2Sx modules, so they can
241 * can be scaled and routed to the I2S GPIO ports, where they
242 * were sampled (using emCORE) to inspect how they behave.
243 * - CG16_SVID seem to be used for external video, this info is
244 * based on OF diagnostics reverse engineering.
245 * - CG16_2L an CG16_5L usage is unknown.
246 */
247#define CG16_SYS (*((volatile uint16_t*)(0x3C500000)))
248#define CG16_2L (*((volatile uint16_t*)(0x3C500008)))
249#define CG16_SVID (*((volatile uint16_t*)(0x3C50000A)))
250#define CG16_AUD0 (*((volatile uint16_t*)(0x3C50000C)))
251#define CG16_AUD1 (*((volatile uint16_t*)(0x3C50000E)))
252#define CG16_AUD2 (*((volatile uint16_t*)(0x3C500010)))
253#define CG16_RTIME (*((volatile uint16_t*)(0x3C500012)))
254#define CG16_5L (*((volatile uint16_t*)(0x3C500014)))
255
256/* CG16 output frequency =
257 !DISABLE_BIT * SEL_x frequency / DIV1+1 / DIV2+1 */
258#define CG16_DISABLE_BIT (1 << 15) /* mask clock output */
259#define CG16_UNK14_BIT (1 << 14) /* writable on CG16_2L */
260
261#define CG16_SEL_POS 12 /* source clock selection */
262#define CG16_SEL_MSK 0x3
263#define CG16_SEL_OSC 0
264#define CG16_SEL_PLL0 1
265#define CG16_SEL_PLL1 2
266#define CG16_SEL_PLL2 3
267
268#define CG16_UNKOSC_BIT (1 << 11)
269
270#define CG16_DIV2_POS 4 /* 2nd divisor */
271#define CG16_DIV2_MSK 0xf
272
273#define CG16_DIV1_POS 0 /* 1st divisor */
274#define CG16_DIV1_MSK 0xf
275
276/*
277 * CLKCON0
278 */
279#define CLKCON0_SDR_DISABLE_BIT (1 << 31)
280
281/*
282 * CLKCON1
283 */
284/* CPU/AHB/APB real_divisor =
285 xDIV_EN_BIT ? 2*(reg_value+1) : 1 */
286#define CLKCON1_CDIV_POS 24
287#define CLKCON1_CDIV_MSK 0x1f
288#define CLKCON1_CDIV_EN_BIT (1 << 30)
289
290#define CLKCON1_HDIV_POS 16
291#define CLKCON1_HDIV_MSK 0x1f
292#define CLKCON1_HDIV_EN_BIT (1 << 22)
293
294#define CLKCON1_PDIV_POS 8
295#define CLKCON1_PDIV_MSK 0x1f
296#define CLKCON1_PDIV_EN_BIT (1 << 14)
297
298/* AHB/APB ratio: must be written when HDIV and/or PDIV
299 are modified, real_ratio = reg_value + 1 */
300#define CLKCON1_HPRAT_POS 0
301#define CLKCON1_HPRAT_MSK 0x3f
302
303/*
304 * CLKCON5
305 */
306/* TBC: this bit selects a clock routed (at least) to all I2S modules
307 * (AUDAUX_Clk, see i2s-s5l8702.h), it can be selected as a source
308 * for CODEC_CLK (MCLK), on iPod Classic AUDAUX_Clk is:
309 * 0 -> 12 MHz (TBC: OSC0 ???)
310 * 1 -> 24 MHz (TBC: 2*OSC0 ???)
311 */
312#define CLKCON5_AUDAUXCLK_BIT (1 << 31)
313
314/*
315 * PLLnPMS
316 */
317#define PLLPMS_PDIV_POS 24 /* pre-divider */
318#define PLLPMS_PDIV_MSK 0x3f
319#define PLLPMS_MDIV_POS 8 /* main divider */
320#define PLLPMS_MDIV_MSK 0xff
321#define PLLPMS_SDIV_POS 0 /* post-divider (2^S) */
322#define PLLPMS_SDIV_MSK 0x7
323
324/*
325 * PLLLOCK
326 */
327/* Start status:
328 0 -> in progress, 1 -> locked */
329#define PLLLOCK_LCK_BIT(n) (1 << (n))
330
331/* Lock status for Divisor Mode (DM):
332 0 -> DM unlocked, 1 -> DM locked */
333#define PLLLOCK_DMLCK_BIT(n) (1 << (4 + (n)))
334
335/*
336 * PLLMODE
337 */
338/* Enable PLL0,1,2:
339 0 -> turned off, 1 -> turned on */
340#define PLLMODE_EN_BIT(n) (1 << (n))
341
342/* Select PMS mode for PLL0,1:
343 0 -> mutiply mode (MM), 1 -> divide mode (DM) */
344#define PLLMODE_PMSMOD_BIT(n) (1 << (4 + (n)))
345
346/* Select DMOSC for PLL2:
347 0 -> DMOSC_STD, 1 -> DMOSC_ALT */
348#define PLLMODE_PLL2DMOSC_BIT (1 << 6)
349
350/* Select oscilator for CG16_SEL_OSC source:
351 0 -> S5L8702_OSC0, 1 -> S5L8702_OSC1 */
352#define PLLMODE_OSCSEL_BIT (1 << 8)
353
354/* Select PLLxClk (a.k.a. "slow mode" (see s3c2440-DS) for PLL0,1,2:
355 O -> S5L8702_OSC1, 1 -> PLLxFreq */
356#define PLLMODE_PLLOUT_BIT(n) (1 << (16 + (n)))
357
358/*
359 * PLLMOD2
360 */
361/* Selects ALTOSCx for PLL0,1,2 when DMOSC == DMOSC_ALT:
362 0 -> S5L8702_ALTOSC0, 1 -> S5L8702_ALTOSC1 */
363#define PLLMOD2_ALTOSC_BIT(n) (1 << (n))
364
365/* Selects DMOSC for PLL0,1:
366 0 -> DMOSC_STD, 1 -> DMOSC_ALT */
367#define PLLMOD2_DMOSC_BIT(n) (1 << (4 + (n)))
368
369
370/* See s3c2440-DS (figure 7.2) for similar SoC reference.
371 *
372 * There are two different PMS modes, PLLxFreq is:
373 * Divide Mode (DM): (F_in * MDIV / PDIV) / 2^SDIV
374 * Multiply Mode (MM): (F_in * MDIV * PDIV) / 2^SDIV
375 *
376 * PLL0 and PLL1 supports DM and MM, PLL2 only supports DM.
377 *
378 * MM uses S5L8702_OSC1. DM oscillator is selected using DMOSC_BIT
379 * and ALTOSC_BIT.
380 *
381 * PLLLOCK_LCK_BIT is not enabled when PLL gets locked, and being
382 * enabled doesn't meant that the PLL is locked. When using MULTIPLY
383 * mode, there is no (known) way to verify that the PLL is locked.
384 * On DIVIDE mode, PLLLOCK_DMLCK_BIT is enabled when the PLL is
385 * locked at the correct frequency.
386 * PLLLOCK_LCK_BIT is enabled only when lock_time expires, lock_time
387 * is configured in PLLCNT as ticks of PClk. The maximum needed time
388 * to get a good lock is ~300nS (TBC).
389 *
390 * TODO: F_vco notes
391 */
392#define PMSMOD_MUL 0
393#define PMSMOD_DIV 1
394#define GET_PMSMOD(pll) (((pll) == 2) \
395 ? PMSMOD_DIV \
396 : ((PLLMODE & PLLMODE_PMSMOD_BIT(pll)) ? PMSMOD_DIV \
397 : PMSMOD_MUL))
398
399#define DMOSC_STD 0
400#define DMOSC_ALT 1
401#define GET_DMOSC(pll) ((((pll) == 2) \
402 ? (PLLMODE & PLLMODE_PLL2DMOSC_BIT) \
403 : (PLLMOD2 & PLLMOD2_DMOSC_BIT(pll))) ? DMOSC_ALT \
404 : DMOSC_STD)
405
406/* available PLL operation modes */
407#define PLLOP_MM 0 /* Multiply Mode, F_in = S5L8702_OSC1 */
408#define PLLOP_DM 1 /* Divisor Mode, F_in = S5L8702_OSC0 */
409#define PLLOP_ALT0 2 /* Divisor Mode, F_in = S5L8702_ALTOSC0 */
410#define PLLOP_ALT1 3 /* Divisor Mode, F_in = S5L8702_ALTOSC1 */
411
412
413/* These are real clock divisor values, to be encoded into registers
414 * as required. We are using fixed FClk:
415 * FClk = CG16_SYS_SEL / fdiv, fdiv >= 1
416 * On Classic CG16_SYS_SEL = 216 MHz from PLL2, fdiv = 1.
417 */
418struct clocking_mode
419{
420 uint8_t cdiv; /* CClk = FClk / cdiv, cdiv = 1,2,4,6,.. */
421 uint8_t hdiv; /* HClk = FClk / hdiv, hdiv = 1,2,4,6,.. */
422 uint8_t hprat; /* PClk = HClk / hprat, hprat >= 1 */
423 uint8_t hsdiv; /* TBC: SM1_Clk = HClk / hsdiv, hsdiv >= 1 */
424};
425
426void clocking_init(struct clocking_mode *modes, int init_level);
427void set_clocking_level(int level);
428unsigned get_system_freqs(unsigned *cclk, unsigned *hclk, unsigned *pclk);
429
430/* debug */
431unsigned pll_get_cfg_freq(int pll);
432unsigned pll_get_out_freq(int pll);
433unsigned soc_get_oscsel_freq(void);
434int soc_get_hsdiv(void);
435
436#endif /* __CLOCKING_S5L8702_H */
diff --git a/firmware/target/arm/s5l8702/debug-s5l8702.c b/firmware/target/arm/s5l8702/debug-s5l8702.c
index a2c6c0b193..fe2044690d 100644
--- a/firmware/target/arm/s5l8702/debug-s5l8702.c
+++ b/firmware/target/arm/s5l8702/debug-s5l8702.c
@@ -33,6 +33,7 @@
33#ifdef HAVE_SERIAL 33#ifdef HAVE_SERIAL
34#include "uc8702.h" 34#include "uc8702.h"
35#endif 35#endif
36#include "clocking-s5l8702.h"
36 37
37#define DEBUG_CANCEL BUTTON_MENU 38#define DEBUG_CANCEL BUTTON_MENU
38 39
@@ -66,9 +67,10 @@ bool dbg_hw_info(void)
66 67
67 if(state == 0) 68 if(state == 0)
68 { 69 {
70 unsigned cpu_hz;
71 get_system_freqs(&cpu_hz, NULL, NULL);
69 _DEBUG_PRINTF("CPU:"); 72 _DEBUG_PRINTF("CPU:");
70 _DEBUG_PRINTF("speed: %d MHz", ((CLKCON0 & 1) ? 73 _DEBUG_PRINTF("speed: %d MHz", cpu_hz / 1000000);
71 CPUFREQ_NORMAL : CPUFREQ_MAX) / 1000000);
72 _DEBUG_PRINTF("current_tick: %d", (unsigned int)current_tick); 74 _DEBUG_PRINTF("current_tick: %d", (unsigned int)current_tick);
73 uint32_t __res; 75 uint32_t __res;
74 asm volatile ("mrc p15, 0, %0, c0, c0, 0" : "=r"(__res)); 76 asm volatile ("mrc p15, 0, %0, c0, c0, 0" : "=r"(__res));
@@ -82,6 +84,31 @@ bool dbg_hw_info(void)
82 84
83 _DEBUG_PRINTF("capture HW: %d", rec_hw_ver); 85 _DEBUG_PRINTF("capture HW: %d", rec_hw_ver);
84 line++; 86 line++;
87
88#ifdef CLOCKING_DEBUG
89 /* show all clocks */
90 unsigned f_clk, c_clk, h_clk, p_clk, l_clk, s_clk;
91
92 f_clk = get_system_freqs(&c_clk, &h_clk, &p_clk);
93 s_clk = h_clk / soc_get_hsdiv();
94 l_clk = h_clk >> ((LCD_CONFIG & 7) + 1); /* div = 2^(val+1) */
95
96 #define MHZ 1000000
97 #define TMHZ 100000
98 _DEBUG_PRINTF("Clocks (MHz):");
99 _DEBUG_PRINTF(" FClk: %d.%d", f_clk / MHZ, (f_clk % MHZ) / TMHZ);
100 _DEBUG_PRINTF(" CPU: %d.%d", c_clk / MHZ, (c_clk % MHZ) / TMHZ);
101 _DEBUG_PRINTF(" AHB: %d.%d", h_clk / MHZ, (h_clk % MHZ) / TMHZ);
102 _DEBUG_PRINTF(" SM1: %d.%d", s_clk / MHZ, (s_clk % MHZ) / TMHZ);
103 _DEBUG_PRINTF(" LCD: %d.%d", l_clk / MHZ, (l_clk % MHZ) / TMHZ);
104 _DEBUG_PRINTF(" APB: %d.%d", p_clk / MHZ, (p_clk % MHZ) / TMHZ);
105 line++;
106 _DEBUG_PRINTF("CG16_SEL_x (Hz):");
107 _DEBUG_PRINTF(" OSC: %d", soc_get_oscsel_freq());
108 for (int i = 0; i < 3; i++)
109 _DEBUG_PRINTF(" PLL%d: %d (%d)", i,
110 pll_get_out_freq(i), pll_get_cfg_freq(i));
111#endif
85 } 112 }
86 else if(state==1) 113 else if(state==1)
87 { 114 {
diff --git a/firmware/target/arm/s5l8702/system-s5l8702.c b/firmware/target/arm/s5l8702/system-s5l8702.c
index 014ed910de..3e84e5cf54 100644
--- a/firmware/target/arm/s5l8702/system-s5l8702.c
+++ b/firmware/target/arm/s5l8702/system-s5l8702.c
@@ -27,6 +27,7 @@
27#include "gpio-s5l8702.h" 27#include "gpio-s5l8702.h"
28#include "dma-s5l8702.h" 28#include "dma-s5l8702.h"
29#include "uart-s5l8702.h" 29#include "uart-s5l8702.h"
30#include "clocking-s5l8702.h"
30 31
31#define default_interrupt(name) \ 32#define default_interrupt(name) \
32 extern __attribute__((weak,alias("UIRQ"))) void name (void) 33 extern __attribute__((weak,alias("UIRQ"))) void name (void)
@@ -180,9 +181,24 @@ void fiq_dummy(void)
180 ); 181 );
181} 182}
182 183
184static struct clocking_mode clk_modes[] =
185{
186 /* cdiv hdiv hprat hsdiv */ /* CClk HClk PClk SM1Clk FPS */
187 { 1, 2, 2, 4 }, /* 216 108 54 27 42 */
188#ifdef HAVE_ADJUSTABLE_CPU_FREQ
189 { 4, 4, 2, 2 }, /* 54 54 27 27 21 */
190#endif
191};
192#define N_CLK_MODES (sizeof(clk_modes) / sizeof(struct clocking_mode))
193
194enum {
195 CLK_BOOST = 0,
196 CLK_UNBOOST = N_CLK_MODES - 1,
197};
183 198
184void system_init(void) 199void system_init(void)
185{ 200{
201 clocking_init(clk_modes, 0);
186 gpio_init(); 202 gpio_init();
187 pmu_init(); 203 pmu_init();
188 dma_init(); 204 dma_init();
@@ -223,61 +239,22 @@ int system_memory_guard(int newmode)
223} 239}
224 240
225#ifdef HAVE_ADJUSTABLE_CPU_FREQ 241#ifdef HAVE_ADJUSTABLE_CPU_FREQ
226
227void set_cpu_frequency(long frequency) 242void set_cpu_frequency(long frequency)
228{ 243{
229 if (cpu_frequency == frequency) 244 if (cpu_frequency == frequency)
230 return; 245 return;
231 246
232 /*
233 * CPU scaling parameters:
234 * CPUFREQ_MAX: CPU = 216MHz, AHB = 108MHz, Vcore = 1.200V
235 * CPUFREQ_NORMAL: CPU = 54MHz, AHB = 54MHz, Vcore = 1.050V
236 *
237 * CLKCON0 sets PLL2->FCLK divider (CPU clock)
238 * CLKCON1 sets FCLK->HCLK divider (AHB clock)
239 *
240 * HCLK is derived from FCLK, the system goes unstable if HCLK
241 * is out of the range 54-108 MHz, so two stages are required to
242 * switch FCLK (216 MHz <-> 54 MHz), adjusting HCLK in between
243 * to ensure system stability.
244 */
245 if (frequency == CPUFREQ_MAX) 247 if (frequency == CPUFREQ_MAX)
246 { 248 {
247 /* Vcore = 1.200V */ 249 pmu_write(0x1e, 0x13); /* Vcore = 1100 mV */
248 pmu_write(0x1e, 0x17); 250 set_clocking_level(CLK_BOOST);
249
250 /* FCLK = PLL2 / 2 (FCLK = 108MHz, HCLK = 108MHz) */
251 CLKCON0 = 0x3011;
252 udelay(50);
253
254 /* HCLK = FCLK / 2 (HCLK = 54MHz) */
255 CLKCON1 = 0x404101;
256 udelay(50);
257
258 /* FCLK = PLL2 (FCLK = 216MHz, HCLK = 108MHz) */
259 CLKCON0 = 0x3000;
260 udelay(100);
261 } 251 }
262 else 252 else
263 { 253 {
264 /* FCLK = PLL2 / 2 (FCLK = 108MHz, HCLK = 54MHz) */ 254 set_clocking_level(CLK_UNBOOST);
265 CLKCON0 = 0x3011; 255 pmu_write(0x1e, 0xf); /* Vcore = 1000 mV */
266 udelay(50);
267
268 /* HCLK = FCLK (HCLK = 108MHz) */
269 CLKCON1 = 0x4001;
270 udelay(50);
271
272 /* FCLK = PLL2 / 4 (FCLK = 54MHz, HCLK = 54MHz) */
273 CLKCON0 = 0x3013;
274 udelay(100);
275
276 /* Vcore = 1.050V */
277 pmu_write(0x1e, 0x11);
278 } 256 }
279 257
280 cpu_frequency = frequency; 258 cpu_frequency = frequency;
281} 259}
282
283#endif 260#endif
diff --git a/firmware/target/arm/s5l8702/system-target.h b/firmware/target/arm/s5l8702/system-target.h
index ba05c2f6fb..43ab28d37b 100644
--- a/firmware/target/arm/s5l8702/system-target.h
+++ b/firmware/target/arm/s5l8702/system-target.h
@@ -24,7 +24,7 @@
24#include "system-arm.h" 24#include "system-arm.h"
25#include "mmu-arm.h" 25#include "mmu-arm.h"
26 26
27#define CPUFREQ_SLEEP 32768 27#define CPUFREQ_SLEEP 32768
28#define CPUFREQ_MAX 216000000 28#define CPUFREQ_MAX 216000000
29#define CPUFREQ_DEFAULT 54000000 29#define CPUFREQ_DEFAULT 54000000
30#define CPUFREQ_NORMAL 54000000 30#define CPUFREQ_NORMAL 54000000