summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWilliam Wilgus <me.theuser@yahoo.com>2018-07-27 23:56:32 +0200
committerWilliam Wilgus <me.theuser@yahoo.com>2018-07-27 23:56:32 +0200
commit6f0320a9535bc1aa81d83fa879ac14d5ee603658 (patch)
tree3b12fc361595ecd2249f391e114036cb30150105
parent400603abdfb4ba7566e0cae8dbed9268f06716dc (diff)
downloadrockbox-6f0320a9535bc1aa81d83fa879ac14d5ee603658.tar.gz
rockbox-6f0320a9535bc1aa81d83fa879ac14d5ee603658.zip
As3525 v1/v2 Add power savings menu
Allow user to select cpu undervolt There have been quite a few issues across the SANSA AMS line related to CPU undervolting while most players show greatly increased runtime some crash. Rather than constanly upping the voltage we now have a setting with a safe value for all players and the option for lower voltages I plan to add a few other options here later such as disk timings and maybe some other clocks/experimental settings Added: Disk Low speed option for AS3525v2 devices cuts frequency to 12 MHz from 24 MHz Added: Disk Low speed option for AS3525v1 devices cuts frequency to 15.5 MHz from 31 MHz Added: I2c Low Speed AS3525 devices, should be bigger improvement for v1 devices Fixed: Debug menu for AS3525v2 No SDSLOT frequency, Showed IDE freq though it is unused Added: DBOP and SSP underclocking affects display on v1/v2 respectively Fixed: debug menu now has SSP frequency, and SSP_CPSR Update: made settings menu more generic Update: cleaned up code Added: Clip v1 & Fuze v1 didn't have HAVE_ADJUSTABLE_CPU_VOLTAGE. not sure why but, waiting on testing to confirm Added: C200v2 and E200v2 devices and HAVE_ADJUSTABLE_CPU_VOLTAGE. Fixed: v1 devices don't like display timing set lower (dbop) v1 devices don't have a divider set for ssp (causes divide by 0) Fixed: ClipZip display lags with Max SSP divider changed from 0xFE to 0x32 Fixed: v1 devices didn't work properly with highspeed sd cards Added code from http://gerrit.rockbox.org/r/#/c/1704/ Added powersave and IDE interface enable/disable Added: V2 devices now have powersave enabled on sd interface Update: cleaned up code, lang defines, added manual entries Update ssp clock mechanism added calculated ssp divider to clipzip Update turn display clock off when clip+ turns off display Fixed: clipzip wrong register for SSP clock Change-Id: I04137682243be92f0f8d8bf1cfa54fbb1965559b TODO: add other players?
-rw-r--r--apps/features.txt4
-rw-r--r--apps/lang/english.lang51
-rw-r--r--apps/menus/settings_menu.c35
-rw-r--r--apps/settings.h19
-rw-r--r--apps/settings_list.c38
-rw-r--r--firmware/export/config.h6
-rw-r--r--firmware/export/config/sansac200v2.h8
-rw-r--r--firmware/export/config/sansaclip.h8
-rw-r--r--firmware/export/config/sansaclipplus.h5
-rw-r--r--firmware/export/config/sansaclipv2.h5
-rw-r--r--firmware/export/config/sansaclipzip.h5
-rw-r--r--firmware/export/config/sansae200v2.h8
-rw-r--r--firmware/export/config/sansafuze.h8
-rw-r--r--firmware/export/config/sansafuzev2.h5
-rw-r--r--firmware/target/arm/as3525/ascodec-as3525.c31
-rw-r--r--firmware/target/arm/as3525/clock-target.h28
-rw-r--r--firmware/target/arm/as3525/sansa-clipplus/lcd-clip-plus.c23
-rw-r--r--firmware/target/arm/as3525/sansa-clipzip/lcd-clipzip.c24
-rw-r--r--firmware/target/arm/as3525/sd-as3525.c138
-rw-r--r--firmware/target/arm/as3525/sd-as3525v2.c26
-rw-r--r--firmware/target/arm/as3525/system-as3525.c70
-rw-r--r--firmware/target/arm/as3525/system-target.h20
-rwxr-xr-xmanual/configure_rockbox/system_options.tex24
23 files changed, 537 insertions, 52 deletions
diff --git a/apps/features.txt b/apps/features.txt
index 3c0b0a3856..39c8422fbd 100644
--- a/apps/features.txt
+++ b/apps/features.txt
@@ -288,3 +288,7 @@ play_frequency
288#if defined(HAVE_BOOTDATA) 288#if defined(HAVE_BOOTDATA)
289boot_data 289boot_data
290#endif 290#endif
291
292#if defined(CONFIG_POWER_SAVING)
293sys_powersaving
294#endif
diff --git a/apps/lang/english.lang b/apps/lang/english.lang
index d4e0697667..fa1b5f2c27 100644
--- a/apps/lang/english.lang
+++ b/apps/lang/english.lang
@@ -13647,3 +13647,54 @@
13647 *: "Disable Touch" 13647 *: "Disable Touch"
13648 </voice> 13648 </voice>
13649</phrase> 13649</phrase>
13650<phrase>
13651 id: LANG_POWER_SAVING_MENU
13652 desc: system clock and voltage settings
13653 user: core
13654 <source>
13655 *: none
13656 sys_powersaving: "Power Saving"
13657 </source>
13658 <dest>
13659 *: none
13660 sys_powersaving: "Power Saving"
13661 </dest>
13662 <voice>
13663 *: none
13664 sys_powersaving: "Power Saving"
13665 </voice>
13666</phrase>
13667<phrase>
13668 id: LANG_CPU
13669 desc: system clock and voltage settings
13670 user: core
13671 <source>
13672 *: none
13673 sys_powersaving: "CPU"
13674 </source>
13675 <dest>
13676 *: none
13677 sys_powersaving: "CPU"
13678 </dest>
13679 <voice>
13680 *: none
13681 sys_powersaving: "CPU"
13682 </voice>
13683</phrase>
13684<phrase>
13685 id: LANG_I2C
13686 desc: system clock and voltage settings
13687 user: core
13688 <source>
13689 *: none
13690 sys_powersaving: "I2C"
13691 </source>
13692 <dest>
13693 *: none
13694 sys_powersaving: "I2C"
13695 </dest>
13696 <voice>
13697 *: none
13698 sys_powersaving: "I2C"
13699 </voice>
13700</phrase>
diff --git a/apps/menus/settings_menu.c b/apps/menus/settings_menu.c
index 5c99cb4cd4..f23f01d4dc 100644
--- a/apps/menus/settings_menu.c
+++ b/apps/menus/settings_menu.c
@@ -295,6 +295,36 @@ MAKE_MENU(disk_menu, ID2P(LANG_DISK_MENU), 0, Icon_NOICON,
295 ); 295 );
296#endif 296#endif
297 297
298#ifdef CONFIG_POWER_SAVING
299#if (CONFIG_POWER_SAVING & POWERSV_CPU)
300MENUITEM_SETTING(cpu_powersave, &global_settings.cpu_powersave, NULL);
301#endif
302#if (CONFIG_POWER_SAVING & POWERSV_DISK)
303MENUITEM_SETTING(disk_powersave, &global_settings.disk_powersave, NULL);
304#endif
305#if (CONFIG_POWER_SAVING & POWERSV_I2C)
306MENUITEM_SETTING(i2c_powersave, &global_settings.i2c_powersave, NULL);
307#endif
308#if (CONFIG_POWER_SAVING & POWERSV_DISP)
309MENUITEM_SETTING(disp_powersave, &global_settings.disp_powersave, NULL);
310#endif
311
312MAKE_MENU(power_save_menu, ID2P(LANG_POWER_SAVING_MENU), 0, Icon_NOICON,
313#if (CONFIG_POWER_SAVING & POWERSV_CPU)
314 &cpu_powersave,
315#endif
316#if (CONFIG_POWER_SAVING & POWERSV_DISK)
317 &disk_powersave,
318#endif
319#if (CONFIG_POWER_SAVING & POWERSV_I2C)
320 &i2c_powersave,
321#endif
322#if (CONFIG_POWER_SAVING & POWERSV_DISP)
323 &disp_powersave,
324#endif
325 );
326#endif /* ifdef CONFIG_POWER_SAVING */
327
298/* Limits menu */ 328/* Limits menu */
299MENUITEM_SETTING(max_files_in_dir, &global_settings.max_files_in_dir, NULL); 329MENUITEM_SETTING(max_files_in_dir, &global_settings.max_files_in_dir, NULL);
300MENUITEM_SETTING(max_files_in_playlist, &global_settings.max_files_in_playlist, NULL); 330MENUITEM_SETTING(max_files_in_playlist, &global_settings.max_files_in_playlist, NULL);
@@ -412,6 +442,11 @@ MAKE_MENU(system_menu, ID2P(LANG_SYSTEM),
412 &disk_menu, 442 &disk_menu,
413#endif 443#endif
414 &limits_menu, 444 &limits_menu,
445
446#if defined(CONFIG_POWER_SAVING)
447 &power_save_menu,
448#endif
449
415#ifdef HAVE_QUICKSCREEN 450#ifdef HAVE_QUICKSCREEN
416 &shortcuts_replaces_quickscreen, 451 &shortcuts_replaces_quickscreen,
417#endif 452#endif
diff --git a/apps/settings.h b/apps/settings.h
index 71233d904a..411675153a 100644
--- a/apps/settings.h
+++ b/apps/settings.h
@@ -860,6 +860,25 @@ struct user_settings
860 int governor; 860 int governor;
861 int usb_mode; 861 int usb_mode;
862#endif 862#endif
863
864#ifdef CONFIG_POWER_SAVING
865#if (CONFIG_POWER_SAVING & POWERSV_CPU)
866 bool cpu_powersave;
867#endif
868
869#if (CONFIG_POWER_SAVING & POWERSV_DISK)
870 bool disk_powersave;
871#endif
872
873#if (CONFIG_POWER_SAVING & POWERSV_I2C)
874 bool i2c_powersave;
875#endif
876
877#if (CONFIG_POWER_SAVING & POWERSV_DISP)
878 bool disp_powersave;
879#endif
880#endif /*defined(CONFIG_POWER_SAVING)*/
881
863}; 882};
864 883
865/** global variables **/ 884/** global variables **/
diff --git a/apps/settings_list.c b/apps/settings_list.c
index 57763d345a..fe280b0ff6 100644
--- a/apps/settings_list.c
+++ b/apps/settings_list.c
@@ -2246,7 +2246,43 @@ const struct settings_list settings[] = {
2246 ID2P(LANG_IBASSO_USB_MODE_CHARGE), 2246 ID2P(LANG_IBASSO_USB_MODE_CHARGE),
2247 ID2P(LANG_IBASSO_USB_MODE_ADB)), 2247 ID2P(LANG_IBASSO_USB_MODE_ADB)),
2248#endif 2248#endif
2249}; 2249
2250#ifdef CONFIG_POWER_SAVING
2251#if (CONFIG_POWER_SAVING & POWERSV_CPU)
2252 OFFON_SETTING(0,
2253 cpu_powersave,
2254 LANG_CPU,
2255 false,
2256 "cpu powersave",
2257 cpu_set_powersave),
2258#endif
2259#if (CONFIG_POWER_SAVING & POWERSV_DISK)
2260 OFFON_SETTING(0,
2261 disk_powersave,
2262 LANG_DISK_MENU,
2263 false,
2264 "disk powersave",
2265 disk_set_powersave),
2266#endif
2267#if (CONFIG_POWER_SAVING & POWERSV_DISP)
2268 OFFON_SETTING(0,
2269 disp_powersave,
2270 LANG_DISPLAY,
2271 false,
2272 "disp powersave",
2273 disp_set_powersave),
2274#endif
2275#if (CONFIG_POWER_SAVING & POWERSV_I2C)
2276 OFFON_SETTING(0,
2277 i2c_powersave,
2278 LANG_I2C,
2279 false,
2280 "i2c powersave",
2281 i2c_set_powersave),
2282#endif
2283#endif /*defined(CONFIG_POWER_SAVING)*/
2284
2285};/*struct settings_list settings*/
2250 2286
2251const int nb_settings = sizeof(settings)/sizeof(*settings); 2287const int nb_settings = sizeof(settings)/sizeof(*settings);
2252 2288
diff --git a/firmware/export/config.h b/firmware/export/config.h
index 14664257bf..e362000c18 100644
--- a/firmware/export/config.h
+++ b/firmware/export/config.h
@@ -168,6 +168,12 @@
168#define SONY_NWZA860_PAD 64 /* The NWZ-A860 is too different (touchscreen) */ 168#define SONY_NWZA860_PAD 64 /* The NWZ-A860 is too different (touchscreen) */
169#define AGPTEK_ROCKER_PAD 65 169#define AGPTEK_ROCKER_PAD 65
170 170
171/* CONFIG_POWER_SAVE combinable bit flags*/
172#define POWERSV_CPU 0x1
173#define POWERSV_I2C 0x2
174#define POWERSV_DISK 0x4
175#define POWERSV_DISP 0x8
176
171/* CONFIG_REMOTE_KEYPAD */ 177/* CONFIG_REMOTE_KEYPAD */
172#define H100_REMOTE 1 178#define H100_REMOTE 1
173#define H300_REMOTE 2 179#define H300_REMOTE 2
diff --git a/firmware/export/config/sansac200v2.h b/firmware/export/config/sansac200v2.h
index a51f9e3b00..98fbb570fb 100644
--- a/firmware/export/config/sansac200v2.h
+++ b/firmware/export/config/sansac200v2.h
@@ -193,6 +193,14 @@
193/* Define this if you have adjustable CPU frequency */ 193/* Define this if you have adjustable CPU frequency */
194#define HAVE_ADJUSTABLE_CPU_FREQ 194#define HAVE_ADJUSTABLE_CPU_FREQ
195 195
196/*define this to enable CPU voltage scaling on AMS devices*/
197#define HAVE_ADJUSTABLE_CPU_VOLTAGE
198
199#ifndef BOOTLOADER
200/*define this with flags for power saving options device supports*/
201#define CONFIG_POWER_SAVING (POWERSV_CPU | POWERSV_I2C | POWERSV_DISK)
202#endif
203
196#define BOOTFILE_EXT "sansa" 204#define BOOTFILE_EXT "sansa"
197#define BOOTFILE "rockbox." BOOTFILE_EXT 205#define BOOTFILE "rockbox." BOOTFILE_EXT
198#define BOOTDIR "/.rockbox" 206#define BOOTDIR "/.rockbox"
diff --git a/firmware/export/config/sansaclip.h b/firmware/export/config/sansaclip.h
index cdee43d44a..f0300c2ac1 100644
--- a/firmware/export/config/sansaclip.h
+++ b/firmware/export/config/sansaclip.h
@@ -186,6 +186,14 @@
186/* Define this if you have adjustable CPU frequency */ 186/* Define this if you have adjustable CPU frequency */
187#define HAVE_ADJUSTABLE_CPU_FREQ 187#define HAVE_ADJUSTABLE_CPU_FREQ
188 188
189/*define this to enable CPU voltage scaling on AMS devices*/
190#define HAVE_ADJUSTABLE_CPU_VOLTAGE
191
192#ifndef BOOTLOADER
193/*define this with flags for power saving options device supports*/
194#define CONFIG_POWER_SAVING (POWERSV_CPU | POWERSV_I2C | POWERSV_DISK)
195#endif
196
189#define BOOTFILE_EXT "sansa" 197#define BOOTFILE_EXT "sansa"
190#define BOOTFILE "rockbox." BOOTFILE_EXT 198#define BOOTFILE "rockbox." BOOTFILE_EXT
191#define BOOTDIR "/.rockbox" 199#define BOOTDIR "/.rockbox"
diff --git a/firmware/export/config/sansaclipplus.h b/firmware/export/config/sansaclipplus.h
index addf7d86c0..9a307420f4 100644
--- a/firmware/export/config/sansaclipplus.h
+++ b/firmware/export/config/sansaclipplus.h
@@ -206,6 +206,11 @@
206/*define this to enable CPU voltage scaling on AMS devices*/ 206/*define this to enable CPU voltage scaling on AMS devices*/
207#define HAVE_ADJUSTABLE_CPU_VOLTAGE 207#define HAVE_ADJUSTABLE_CPU_VOLTAGE
208 208
209#ifndef BOOTLOADER
210/*define this with flags for power saving options device supports*/
211#define CONFIG_POWER_SAVING (POWERSV_CPU | POWERSV_I2C | POWERSV_DISK | POWERSV_DISP)
212#endif
213
209#define BOOTFILE_EXT "sansa" 214#define BOOTFILE_EXT "sansa"
210#define BOOTFILE "rockbox." BOOTFILE_EXT 215#define BOOTFILE "rockbox." BOOTFILE_EXT
211#define BOOTDIR "/.rockbox" 216#define BOOTDIR "/.rockbox"
diff --git a/firmware/export/config/sansaclipv2.h b/firmware/export/config/sansaclipv2.h
index cf3f90e363..81a0d4703f 100644
--- a/firmware/export/config/sansaclipv2.h
+++ b/firmware/export/config/sansaclipv2.h
@@ -200,6 +200,11 @@
200/*define this to enable CPU voltage scaling on AMS devices*/ 200/*define this to enable CPU voltage scaling on AMS devices*/
201#define HAVE_ADJUSTABLE_CPU_VOLTAGE 201#define HAVE_ADJUSTABLE_CPU_VOLTAGE
202 202
203#ifndef BOOTLOADER
204/*define this with flags for power saving options device supports*/
205#define CONFIG_POWER_SAVING (POWERSV_CPU | POWERSV_I2C | POWERSV_DISK)
206#endif
207
203#define BOOTFILE_EXT "sansa" 208#define BOOTFILE_EXT "sansa"
204#define BOOTFILE "rockbox." BOOTFILE_EXT 209#define BOOTFILE "rockbox." BOOTFILE_EXT
205#define BOOTDIR "/.rockbox" 210#define BOOTDIR "/.rockbox"
diff --git a/firmware/export/config/sansaclipzip.h b/firmware/export/config/sansaclipzip.h
index fc9f558eef..8464603c34 100644
--- a/firmware/export/config/sansaclipzip.h
+++ b/firmware/export/config/sansaclipzip.h
@@ -205,6 +205,11 @@
205/*define this to enable CPU voltage scaling on AMS devices*/ 205/*define this to enable CPU voltage scaling on AMS devices*/
206#define HAVE_ADJUSTABLE_CPU_VOLTAGE 206#define HAVE_ADJUSTABLE_CPU_VOLTAGE
207 207
208#ifndef BOOTLOADER
209/*define this with flags for power saving options device supports*/
210#define CONFIG_POWER_SAVING (POWERSV_CPU | POWERSV_I2C | POWERSV_DISK | POWERSV_DISP)
211#endif
212
208#define BOOTFILE_EXT "sansa" 213#define BOOTFILE_EXT "sansa"
209#define BOOTFILE "rockbox." BOOTFILE_EXT 214#define BOOTFILE "rockbox." BOOTFILE_EXT
210#define BOOTDIR "/.rockbox" 215#define BOOTDIR "/.rockbox"
diff --git a/firmware/export/config/sansae200v2.h b/firmware/export/config/sansae200v2.h
index 96b51f4e12..50e1843189 100644
--- a/firmware/export/config/sansae200v2.h
+++ b/firmware/export/config/sansae200v2.h
@@ -213,6 +213,14 @@
213/* Define this if you have adjustable CPU frequency */ 213/* Define this if you have adjustable CPU frequency */
214#define HAVE_ADJUSTABLE_CPU_FREQ 214#define HAVE_ADJUSTABLE_CPU_FREQ
215 215
216/*define this to enable CPU voltage scaling on AMS devices*/
217#define HAVE_ADJUSTABLE_CPU_VOLTAGE
218
219#ifndef BOOTLOADER
220/*define this with flags for power saving options device supports*/
221#define CONFIG_POWER_SAVING (POWERSV_CPU | POWERSV_I2C | POWERSV_DISK)
222#endif
223
216#define BOOTFILE_EXT "sansa" 224#define BOOTFILE_EXT "sansa"
217#define BOOTFILE "rockbox." BOOTFILE_EXT 225#define BOOTFILE "rockbox." BOOTFILE_EXT
218#define BOOTDIR "/.rockbox" 226#define BOOTDIR "/.rockbox"
diff --git a/firmware/export/config/sansafuze.h b/firmware/export/config/sansafuze.h
index fae3463d75..dedf8c44da 100644
--- a/firmware/export/config/sansafuze.h
+++ b/firmware/export/config/sansafuze.h
@@ -219,6 +219,14 @@
219/* Define this if you have adjustable CPU frequency */ 219/* Define this if you have adjustable CPU frequency */
220#define HAVE_ADJUSTABLE_CPU_FREQ 220#define HAVE_ADJUSTABLE_CPU_FREQ
221 221
222/*define this to enable CPU voltage scaling on AMS devices*/
223#define HAVE_ADJUSTABLE_CPU_VOLTAGE
224
225#ifndef BOOTLOADER
226/*define this with flags for power saving options device supports*/
227#define CONFIG_POWER_SAVING (POWERSV_CPU | POWERSV_I2C | POWERSV_DISK)
228#endif
229
222#define BOOTFILE_EXT "sansa" 230#define BOOTFILE_EXT "sansa"
223#define BOOTFILE "rockbox." BOOTFILE_EXT 231#define BOOTFILE "rockbox." BOOTFILE_EXT
224#define BOOTDIR "/.rockbox" 232#define BOOTDIR "/.rockbox"
diff --git a/firmware/export/config/sansafuzev2.h b/firmware/export/config/sansafuzev2.h
index b85e0747a3..3190930b56 100644
--- a/firmware/export/config/sansafuzev2.h
+++ b/firmware/export/config/sansafuzev2.h
@@ -224,6 +224,11 @@
224/*define this to enable CPU voltage scaling on AMS devices*/ 224/*define this to enable CPU voltage scaling on AMS devices*/
225#define HAVE_ADJUSTABLE_CPU_VOLTAGE 225#define HAVE_ADJUSTABLE_CPU_VOLTAGE
226 226
227#ifndef BOOTLOADER
228/*define this with flags for power saving options device supports*/
229#define CONFIG_POWER_SAVING (POWERSV_CPU | POWERSV_I2C | POWERSV_DISK)
230#endif
231
227#define BOOTFILE_EXT "sansa" 232#define BOOTFILE_EXT "sansa"
228#define BOOTFILE "rockbox." BOOTFILE_EXT 233#define BOOTFILE "rockbox." BOOTFILE_EXT
229#define BOOTDIR "/.rockbox" 234#define BOOTDIR "/.rockbox"
diff --git a/firmware/target/arm/as3525/ascodec-as3525.c b/firmware/target/arm/as3525/ascodec-as3525.c
index 14c3ee7a36..d23859e420 100644
--- a/firmware/target/arm/as3525/ascodec-as3525.c
+++ b/firmware/target/arm/as3525/ascodec-as3525.c
@@ -623,11 +623,25 @@ void i2c_init(void)
623 /* required function but called too late for our needs */ 623 /* required function but called too late for our needs */
624} 624}
625 625
626static void i2c_set_prescaler(unsigned int prescaler)
627{
628 int oldlevel = disable_interrupt_save(IRQ_FIQ_STATUS);
629 /* must be on to write regs */
630 bool i2c_enabled = bitset32(&CGU_PERI, CGU_I2C_AUDIO_MASTER_CLOCK_ENABLE) &
631 CGU_I2C_AUDIO_MASTER_CLOCK_ENABLE;
632
633 I2C2_CPSR0 = prescaler & 0xFF; /* 8 lsb */
634 I2C2_CPSR1 = (prescaler >> 8) & 0x3; /* 2 msb */
635
636 if (!i2c_enabled) /* put it back how we found it */
637 bitclr32(&CGU_PERI, CGU_I2C_AUDIO_MASTER_CLOCK_ENABLE);
638
639 restore_irq(oldlevel);
640}
641
626/* initialises the internal i2c bus and prepares for transfers to the codec */ 642/* initialises the internal i2c bus and prepares for transfers to the codec */
627void ascodec_init(void) 643void ascodec_init(void)
628{ 644{
629 int prescaler;
630
631 ll_init(&req_list); 645 ll_init(&req_list);
632 mutex_init(&as_mtx); 646 mutex_init(&as_mtx);
633 ascodec_async_init(&as_audio_req, ascodec_int_audio_cb, 0); 647 ascodec_async_init(&as_audio_req, ascodec_int_audio_cb, 0);
@@ -637,9 +651,7 @@ void ascodec_init(void)
637 bitset32(&CGU_PERI, CGU_I2C_AUDIO_MASTER_CLOCK_ENABLE); 651 bitset32(&CGU_PERI, CGU_I2C_AUDIO_MASTER_CLOCK_ENABLE);
638 652
639 /* prescaler for i2c clock */ 653 /* prescaler for i2c clock */
640 prescaler = AS3525_I2C_PRESCALER; 654 i2c_set_prescaler(AS3525_I2C_PRESCALER);
641 I2C2_CPSR0 = prescaler & 0xFF; /* 8 lsb */
642 I2C2_CPSR1 = (prescaler >> 8) & 0x3; /* 2 msb */
643 655
644 /* set i2c slave address of codec part */ 656 /* set i2c slave address of codec part */
645 I2C2_SLAD0 = AS3514_I2C_ADDR << 1; 657 I2C2_SLAD0 = AS3514_I2C_ADDR << 1;
@@ -690,3 +702,12 @@ void ams_i2c_get_debug_cpsr(unsigned int *i2c_cpsr)
690 702
691 restore_irq(oldlevel); 703 restore_irq(oldlevel);
692} 704}
705
706#if defined(CONFIG_POWER_SAVING) && (CONFIG_POWER_SAVING & POWERSV_I2C)
707/* declared in system-as3525.c */
708void ams_i2c_set_low_speed(bool slow)
709{
710 i2c_set_prescaler(slow ? AS3525_I2C_PRESCALER_MAX : AS3525_I2C_PRESCALER);
711}
712#endif
713
diff --git a/firmware/target/arm/as3525/clock-target.h b/firmware/target/arm/as3525/clock-target.h
index 7f6b17eff4..c45529dfda 100644
--- a/firmware/target/arm/as3525/clock-target.h
+++ b/firmware/target/arm/as3525/clock-target.h
@@ -158,22 +158,32 @@
158#endif /* CONFIG_CPU */ 158#endif /* CONFIG_CPU */
159 159
160 /* PCLK as Source */ 160 /* PCLK as Source */
161 #define AS3525_DBOP_DIV (CLK_DIV(AS3525_PCLK_FREQ, AS3525_DBOP_FREQ) - 1) /*div=1/(n+1)*/ 161 #define AS3525_DBOP_DIV (CLK_DIV(AS3525_PCLK_FREQ, AS3525_DBOP_FREQ) - 1) /*div=1/(n+1)*/
162 #define AS3525_I2C_PRESCALER CLK_DIV(AS3525_PCLK_FREQ, AS3525_I2C_FREQ) 162 #define AS3525_I2C_PRESCALER CLK_DIV(AS3525_PCLK_FREQ, AS3525_I2C_FREQ)
163 #define AS3525_I2C_FREQ 400000 163 #define AS3525_I2C_PRESCALER_MAX 0xFF | 0x300 /* Max value for prescaler */
164 #define AS3525_SD_IDENT_DIV ((CLK_DIV(AS3525_PCLK_FREQ, AS3525_SD_IDENT_FREQ) / 2) - 1) 164 #define AS3525_I2C_FREQ 400000
165 #define AS3525_SD_IDENT_FREQ 400000 /* must be between 100 & 400 kHz */ 165 #define AS3525_SD_IDENT_DIV ((CLK_DIV(AS3525_PCLK_FREQ, AS3525_SD_IDENT_FREQ) / 2) - 1)
166 #define AS3525_SSP_PRESCALER ((CLK_DIV(AS3525_PCLK_FREQ, AS3525_SSP_FREQ) + 1) & ~1) /* must be an even number */ 166 #define AS3525_SD_IDENT_FREQ 400000 /* must be between 100 & 400 kHz */
167 #define AS3525_SSP_FREQ 12000000 167 #define AS3525_SSP_PRESCALER ((CLK_DIV(AS3525_PCLK_FREQ, AS3525_SSP_FREQ) + 1) & ~1) /* must be an even number */
168#if LCD_DEPTH > 1
169 #define AS3525_SSP_PRESCALER_MAX ((CLK_DIV(AS3525_PCLK_FREQ, AS3525_SSP_FREQ_MIN) + 1) & ~1)/* must be an even number */
170 #define AS3525_SSP_FREQ_MIN 2000000 /* 2 MHz gives a decent refresh rate on clipzip*/
171#else
172 #define AS3525_SSP_PRESCALER_MAX 0xFE & ~1 /*Max value for divider - must be an even number */
173 #define AS3525_SSP_FREQ_MIN AS3525_SSP_FREQ /* No set minimum we just use max divider */
174#endif
175 #define AS3525_SSP_FREQ 12000000
168 176
169#define AS3525_IDE_SEL AS3525_CLK_PLLA /* Input Source */ 177#define AS3525_IDE_SEL AS3525_CLK_PLLA /* Input Source */
170#define AS3525_IDE_DIV (CLK_DIV(AS3525_PLLA_FREQ, AS3525_IDE_FREQ) - 1)/*div=1/(n+1)*/ 178#define AS3525_IDE_DIV (CLK_DIV(AS3525_PLLA_FREQ, AS3525_IDE_FREQ) - 1)/*div=1/(n+1)*/
179#define AS3525_IDE_DIV_MAX 0xF /* Max value for divider */
171 180
172#if CONFIG_CPU == AS3525v2 181#if CONFIG_CPU == AS3525v2
173#define AS3525_MS_FREQ 120000000 182#define AS3525_MS_FREQ 120000000
174#define AS3525_MS_DIV (CLK_DIV(AS3525_PLLA_FREQ, AS3525_MS_FREQ) -1) 183#define AS3525_MS_DIV (CLK_DIV(AS3525_PLLA_FREQ, AS3525_MS_FREQ) -1)
175#define AS3525_SDSLOT_FREQ 24000000 184#define AS3525_SDSLOT_FREQ 24000000
176#define AS3525_SDSLOT_DIV (CLK_DIV(AS3525_PLLA_FREQ, AS3525_SDSLOT_FREQ) -1) 185#define AS3525_SDSLOT_DIV (CLK_DIV(AS3525_PLLA_FREQ, AS3525_SDSLOT_FREQ) -1)
186#define AS3525_SDSLOT_DIV_MAX 0xF /* Max value for divider */
177#define AS3525_IDE_FREQ 80000000 187#define AS3525_IDE_FREQ 80000000
178#else 188#else
179#define AS3525_IDE_FREQ 50000000 /* The OF uses 66MHz maximal freq */ 189#define AS3525_IDE_FREQ 50000000 /* The OF uses 66MHz maximal freq */
@@ -211,6 +221,10 @@
211#error SSP frequency is too low : clock divider will not fit ! 221#error SSP frequency is too low : clock divider will not fit !
212#endif 222#endif
213 223
224#if (((CLK_DIV(AS3525_PCLK_FREQ, AS3525_SSP_FREQ_MIN)) + 1 ) & ~1) >= (1<<8) /* 8 bits */
225#error SSP_MIN frequency is too low : clock divider will not fit !
226#endif
227
214/* AS3525_SD_IDENT_FREQ */ 228/* AS3525_SD_IDENT_FREQ */
215#if ((CLK_DIV(AS3525_PCLK_FREQ, AS3525_SD_IDENT_FREQ) / 2) - 1) >= (1<<8) /* 8 bits */ 229#if ((CLK_DIV(AS3525_PCLK_FREQ, AS3525_SD_IDENT_FREQ) / 2) - 1) >= (1<<8) /* 8 bits */
216#error SD IDENTIFICATION frequency is too low : clock divider will not fit ! 230#error SD IDENTIFICATION frequency is too low : clock divider will not fit !
diff --git a/firmware/target/arm/as3525/sansa-clipplus/lcd-clip-plus.c b/firmware/target/arm/as3525/sansa-clipplus/lcd-clip-plus.c
index a50a9e5c80..7c0cfb5345 100644
--- a/firmware/target/arm/as3525/sansa-clipplus/lcd-clip-plus.c
+++ b/firmware/target/arm/as3525/sansa-clipplus/lcd-clip-plus.c
@@ -26,11 +26,25 @@
26#include "system.h" 26#include "system.h"
27#include "cpu.h" 27#include "cpu.h"
28 28
29static void ssp_set_prescaler(unsigned int prescaler)
30{
31 int oldlevel = disable_interrupt_save(IRQ_FIQ_STATUS);
32 /* must be on to write regs */
33 bool ssp_enabled = bitset32(&CGU_PERI, CGU_SSP_CLOCK_ENABLE) &
34 CGU_SSP_CLOCK_ENABLE;
35 SSP_CPSR = prescaler;
36
37 if (!ssp_enabled) /* put it back how we found it */
38 bitclr32(&CGU_PERI, CGU_SSP_CLOCK_ENABLE);
39
40 restore_irq(oldlevel);
41}
42
29int lcd_hw_init(void) 43int lcd_hw_init(void)
30{ 44{
31 bitset32(&CGU_PERI, CGU_SSP_CLOCK_ENABLE); 45 bitset32(&CGU_PERI, CGU_SSP_CLOCK_ENABLE);
32 46
33 SSP_CPSR = AS3525_SSP_PRESCALER; /* OF = 0x10 */ 47 ssp_set_prescaler(AS3525_SSP_PRESCALER); /* OF = 0x10 */
34 SSP_CR0 = (1<<7) | (1<<6) | 7; /* Motorola SPI frame format, 8 bits */ 48 SSP_CR0 = (1<<7) | (1<<6) | 7; /* Motorola SPI frame format, 8 bits */
35 SSP_CR1 = (1<<3) | (1<<1); /* SSP Operation enabled */ 49 SSP_CR1 = (1<<3) | (1<<1); /* SSP Operation enabled */
36 SSP_IMSC = 0; /* No interrupts */ 50 SSP_IMSC = 0; /* No interrupts */
@@ -115,3 +129,10 @@ void lcd_enable_power(bool onoff)
115#endif 129#endif
116} 130}
117 131
132#if defined(CONFIG_POWER_SAVING) && (CONFIG_POWER_SAVING & POWERSV_DISP)
133/* declared in system-as3525.c */
134void ams_ssp_set_low_speed(bool slow)
135{
136 ssp_set_prescaler(slow ? AS3525_SSP_PRESCALER_MAX : AS3525_SSP_PRESCALER);
137}
138#endif
diff --git a/firmware/target/arm/as3525/sansa-clipzip/lcd-clipzip.c b/firmware/target/arm/as3525/sansa-clipzip/lcd-clipzip.c
index e17bfc421b..8a3df517fb 100644
--- a/firmware/target/arm/as3525/sansa-clipzip/lcd-clipzip.c
+++ b/firmware/target/arm/as3525/sansa-clipzip/lcd-clipzip.c
@@ -35,12 +35,26 @@ static int lcd_type;
35static bool lcd_enabled; 35static bool lcd_enabled;
36#endif 36#endif
37 37
38static void ssp_set_prescaler(unsigned int prescaler)
39{
40 int oldlevel = disable_interrupt_save(IRQ_FIQ_STATUS);
41 /* must be on to write regs */
42 bool ssp_enabled = bitset32(&CGU_PERI, CGU_SSP_CLOCK_ENABLE) &
43 CGU_SSP_CLOCK_ENABLE;
44 SSP_CPSR = prescaler;
45
46 if (!ssp_enabled) /* put it back how we found it */
47 bitclr32(&CGU_PERI, CGU_SSP_CLOCK_ENABLE);
48
49 restore_irq(oldlevel);
50}
51
38/* initialises the host lcd hardware, returns the lcd type */ 52/* initialises the host lcd hardware, returns the lcd type */
39static int lcd_hw_init(void) 53static int lcd_hw_init(void)
40{ 54{
41 /* configure SSP */ 55 /* configure SSP */
42 bitset32(&CGU_PERI, CGU_SSP_CLOCK_ENABLE); 56 bitset32(&CGU_PERI, CGU_SSP_CLOCK_ENABLE);
43 SSP_CPSR = 4; /* TODO: use AS3525_SSP_PRESCALER, OF uses 8 */ 57 ssp_set_prescaler(AS3525_SSP_PRESCALER); /* OF = 0x8 */
44 SSP_CR0 = (0 << 8) | /* SCR, serial clock rate divider = 1 */ 58 SSP_CR0 = (0 << 8) | /* SCR, serial clock rate divider = 1 */
45 (1 << 7) | /* SPH, phase = 1 */ 59 (1 << 7) | /* SPH, phase = 1 */
46 (1 << 6) | /* SPO, polarity = 1 */ 60 (1 << 6) | /* SPO, polarity = 1 */
@@ -437,3 +451,11 @@ void lcd_update(void)
437{ 451{
438 lcd_update_rect(0, 0, LCD_WIDTH, LCD_HEIGHT); 452 lcd_update_rect(0, 0, LCD_WIDTH, LCD_HEIGHT);
439} 453}
454
455#if defined(CONFIG_POWER_SAVING) && (CONFIG_POWER_SAVING & POWERSV_DISP)
456/* declared in system-as3525.c */
457void ams_ssp_set_low_speed(bool slow)
458{
459 ssp_set_prescaler(slow ? AS3525_SSP_PRESCALER_MAX : AS3525_SSP_PRESCALER);
460}
461#endif
diff --git a/firmware/target/arm/as3525/sd-as3525.c b/firmware/target/arm/as3525/sd-as3525.c
index 494a76a782..9e4a86acbe 100644
--- a/firmware/target/arm/as3525/sd-as3525.c
+++ b/firmware/target/arm/as3525/sd-as3525.c
@@ -89,6 +89,8 @@
89 | MCI_CMD_CRC_FAIL) 89 | MCI_CMD_CRC_FAIL)
90 90
91#define MCI_FIFO(i) ((unsigned long *) (pl180_base[i]+0x80)) 91#define MCI_FIFO(i) ((unsigned long *) (pl180_base[i]+0x80))
92
93#define IDE_INTERFACE_CLK (1<<6) /* non AHB interface */
92/* volumes */ 94/* volumes */
93#define INTERNAL_AS3525 0 /* embedded SD card */ 95#define INTERNAL_AS3525 0 /* embedded SD card */
94#define SD_SLOT_AS3525 1 /* SD slot if present */ 96#define SD_SLOT_AS3525 1 /* SD slot if present */
@@ -109,7 +111,8 @@ static void init_pl180_controller(const int drive);
109 111
110static tCardInfo card_info[NUM_DRIVES]; 112static tCardInfo card_info[NUM_DRIVES];
111 113
112/* maximum timeouts recommanded in the SD Specification v2.00 */ 114/* maximum timeouts recommended in the SD Specification v2.00 */
115/* MCI_DATA_TIMER register data timeout in card bus clock periods */
113#define SD_MAX_READ_TIMEOUT ((AS3525_PCLK_FREQ) / 1000 * 100) /* 100 ms */ 116#define SD_MAX_READ_TIMEOUT ((AS3525_PCLK_FREQ) / 1000 * 100) /* 100 ms */
114#define SD_MAX_WRITE_TIMEOUT ((AS3525_PCLK_FREQ) / 1000 * 250) /* 250 ms */ 117#define SD_MAX_WRITE_TIMEOUT ((AS3525_PCLK_FREQ) / 1000 * 250) /* 250 ms */
115 118
@@ -143,7 +146,17 @@ static unsigned char *uncached_buffer = AS3525_UNCACHED_ADDR(&aligned_buffer[0])
143 146
144static inline void mci_delay(void) { udelay(1000) ; } 147static inline void mci_delay(void) { udelay(1000) ; }
145 148
146static void enable_controller(bool on) 149static inline bool card_detect_target(void)
150{
151#if defined(HAVE_MULTIDRIVE)
152 return !(GPIOA_PIN(2));
153#else
154 return false;
155#endif
156}
157
158#if defined(HAVE_MULTIDRIVE) || defined(HAVE_HOTSWAP)
159static void enable_controller_mci(bool on)
147{ 160{
148 161
149#if defined(HAVE_BUTTON_LIGHT) && defined(HAVE_MULTIDRIVE) 162#if defined(HAVE_BUTTON_LIGHT) && defined(HAVE_MULTIDRIVE)
@@ -197,17 +210,33 @@ static void enable_controller(bool on)
197#endif 210#endif
198 } 211 }
199} 212}
213#endif /* defined(HAVE_MULTIDRIVE) || defined(HAVE_HOTSWAP) */
200 214
201static inline bool card_detect_target(void) 215/* AMS v1 have two different drive interfaces MCI_SD(XPD) and GGU_IDE */
216static void enable_controller(bool on, const int drive)
202{ 217{
203#if defined(HAVE_MULTIDRIVE) 218
204 return !(GPIOA_PIN(2)); 219 if (drive == INTERNAL_AS3525)
205#else 220 {
206 return false; 221#ifndef BOOTLOADER
222 if (on)
223 {
224 bitset32(&CGU_PERI, CGU_NAF_CLOCK_ENABLE);
225 CGU_IDE |= IDE_INTERFACE_CLK; /* interface enable */
226 }
227 else
228 {
229 CGU_IDE &= ~(IDE_INTERFACE_CLK); /* interface disable */
230 bitclr32(&CGU_PERI, CGU_NAF_CLOCK_ENABLE);
231 }
232#endif
233 }
234#if defined(HAVE_MULTIDRIVE) || defined(HAVE_HOTSWAP)
235 else
236 enable_controller_mci(on);
207#endif 237#endif
208} 238}
209 239
210
211#ifdef HAVE_HOTSWAP 240#ifdef HAVE_HOTSWAP
212static int sd1_oneshot_callback(struct timeout *tmo) 241static int sd1_oneshot_callback(struct timeout *tmo)
213{ 242{
@@ -326,6 +355,7 @@ static bool send_cmd(const int drive, const int cmd, const int arg,
326 return false; 355 return false;
327} 356}
328 357
358/* MCI_CLOCK = MCLK / 2x(ClkDiv[bits 7:0]+1) */
329#define MCI_FULLSPEED (MCI_CLOCK_ENABLE | MCI_CLOCK_BYPASS) /* MCLK */ 359#define MCI_FULLSPEED (MCI_CLOCK_ENABLE | MCI_CLOCK_BYPASS) /* MCLK */
330#define MCI_HALFSPEED (MCI_CLOCK_ENABLE) /* MCLK/2 */ 360#define MCI_HALFSPEED (MCI_CLOCK_ENABLE) /* MCLK/2 */
331#define MCI_QUARTERSPEED (MCI_CLOCK_ENABLE | 1) /* MCLK/4 */ 361#define MCI_QUARTERSPEED (MCI_CLOCK_ENABLE | 1) /* MCLK/4 */
@@ -345,7 +375,7 @@ static int sd_init_card(const int drive)
345 /* 100 - 400kHz clock required for Identification Mode */ 375 /* 100 - 400kHz clock required for Identification Mode */
346 /* Start of Card Identification Mode ************************************/ 376 /* Start of Card Identification Mode ************************************/
347 377
348 /* CMD0 Go Idle */ 378 /* CMD0 Go Idle -- all card functions switch back to default */
349 if(!send_cmd(drive, SD_GO_IDLE_STATE, 0, MCI_NO_RESP, NULL)) 379 if(!send_cmd(drive, SD_GO_IDLE_STATE, 0, MCI_NO_RESP, NULL))
350 return -1; 380 return -1;
351 mci_delay(); 381 mci_delay();
@@ -393,10 +423,10 @@ static int sd_init_card(const int drive)
393 423
394 if(sd_wait_for_tran_state(drive)) 424 if(sd_wait_for_tran_state(drive))
395 return -6; 425 return -6;
396 /* CMD6 */ 426 /* CMD6 0xf indicates no influence, [3:0],0x1 - HS Access*/
397 if(!send_cmd(drive, SD_SWITCH_FUNC, 0x80fffff1, MCI_NO_RESP, NULL)) 427 if(!send_cmd(drive, SD_SWITCH_FUNC, 0x80fffff1, MCI_NO_RESP, NULL))
398 return -7; 428 return -7;
399 sleep(HZ/10); 429 sleep(HZ/10);/* need to wait at least 8 clock periods */
400 430
401 /* go back to STBY state so we can read csd */ 431 /* go back to STBY state so we can read csd */
402 /* CMD7 w/rca=0: Deselect card to put it in STBY state */ 432 /* CMD7 w/rca=0: Deselect card to put it in STBY state */
@@ -517,7 +547,7 @@ static void init_pl180_controller(const int drive)
517int sd_init(void) 547int sd_init(void)
518{ 548{
519 int ret; 549 int ret;
520 CGU_IDE = (1<<6) /* enable non AHB interface*/ 550 CGU_IDE = IDE_INTERFACE_CLK /* enable interface */
521 | (AS3525_IDE_DIV << 2) 551 | (AS3525_IDE_DIV << 2)
522 | AS3525_CLK_PLLA; /* clock source = PLLA */ 552 | AS3525_CLK_PLLA; /* clock source = PLLA */
523 553
@@ -540,7 +570,9 @@ int sd_init(void)
540 /* init mutex */ 570 /* init mutex */
541 mutex_init(&sd_mtx); 571 mutex_init(&sd_mtx);
542 572
543 enable_controller(false); 573 for (int i = 0; i < NUM_DRIVES ; i++)
574 enable_controller(false, i);
575
544 return 0; 576 return 0;
545} 577}
546 578
@@ -656,7 +688,7 @@ static int sd_transfer_sectors(IF_MD(int drive,) unsigned long start,
656 unsigned long response; 688 unsigned long response;
657 bool aligned = !((uintptr_t)buf & (CACHEALIGN_SIZE - 1)); 689 bool aligned = !((uintptr_t)buf & (CACHEALIGN_SIZE - 1));
658 690
659 enable_controller(true); 691 enable_controller(true, drive);
660 led(true); 692 led(true);
661 693
662 if (card_info[drive].initialized <= 0) 694 if (card_info[drive].initialized <= 0)
@@ -692,27 +724,21 @@ static int sd_transfer_sectors(IF_MD(int drive,) unsigned long start,
692 else 724 else
693 discard_dcache_range(buf, count * SECTOR_SIZE); 725 discard_dcache_range(buf, count * SECTOR_SIZE);
694 } 726 }
695 727 const int cmd = write ? SD_WRITE_MULTIPLE_BLOCK : SD_READ_MULTIPLE_BLOCK;
696 while(count) 728 while(count > 0)
697 { 729 {
698 /* 128 * 512 = 2^16, and doesn't fit in the 16 bits of DATA_LENGTH 730 /* 128 * 512 = 2^16, and doesn't fit in the 16 bits of DATA_LENGTH
699 * register, so we have to transfer maximum 127 sectors at a time. */ 731 * register, so we have to transfer maximum 127 sectors at a time. */
700 unsigned int transfer = (count >= 128) ? 127 : count; /* sectors */ 732 unsigned int transfer = (count >= 128) ? 127 : count; /* sectors */
701 void *dma_buf; 733 void *dma_buf;
702 const int cmd = 734
703 write ? SD_WRITE_MULTIPLE_BLOCK : SD_READ_MULTIPLE_BLOCK;
704 unsigned long bank_start = start; 735 unsigned long bank_start = start;
705 unsigned long status;
706 736
707 /* Only switch banks for internal storage */ 737 /* Only switch banks for internal storage */
708 if(drive == INTERNAL_AS3525) 738 if(drive == INTERNAL_AS3525)
709 { 739 {
710 unsigned int bank = 0; 740 unsigned int bank = bank_start / BLOCKS_PER_BANK;
711 while(bank_start >= BLOCKS_PER_BANK) 741 bank_start -= bank * BLOCKS_PER_BANK;
712 {
713 bank_start -= BLOCKS_PER_BANK;
714 bank++;
715 }
716 742
717 /* Switch bank if needed */ 743 /* Switch bank if needed */
718 if(card_info[INTERNAL_AS3525].current_bank != bank) 744 if(card_info[INTERNAL_AS3525].current_bank != bank)
@@ -770,10 +796,7 @@ static int sd_transfer_sectors(IF_MD(int drive,) unsigned long start,
770 /*Small delay for writes prevents data crc failures at lower freqs*/ 796 /*Small delay for writes prevents data crc failures at lower freqs*/
771#ifdef HAVE_MULTIDRIVE 797#ifdef HAVE_MULTIDRIVE
772 if((drive == SD_SLOT_AS3525) && !hs_card) 798 if((drive == SD_SLOT_AS3525) && !hs_card)
773 { 799 udelay(4);
774 int write_delay = 125;
775 while(write_delay--);
776 }
777#endif 800#endif
778 } 801 }
779 else 802 else
@@ -804,7 +827,7 @@ static int sd_transfer_sectors(IF_MD(int drive,) unsigned long start,
804 827
805 last_disk_activity = current_tick; 828 last_disk_activity = current_tick;
806 829
807 if(!send_cmd(drive, SD_STOP_TRANSMISSION, 0, MCI_RESP, &status)) 830 if(!send_cmd(drive, SD_STOP_TRANSMISSION, 0, MCI_RESP, &response))
808 { 831 {
809 ret = -4*20; 832 ret = -4*20;
810 goto sd_transfer_error; 833 goto sd_transfer_error;
@@ -831,7 +854,7 @@ sd_transfer_error:
831sd_transfer_error_nodma: 854sd_transfer_error_nodma:
832 855
833 led(false); 856 led(false);
834 enable_controller(false); 857 enable_controller(false, drive);
835 858
836 if (ret) /* error */ 859 if (ret) /* error */
837 card_info[drive].initialized = 0; 860 card_info[drive].initialized = 0;
@@ -922,12 +945,18 @@ void ams_sd_get_debug_info(struct ams_sd_debug_info *info)
922 #define MCI_SD *((volatile unsigned long *)(SD_MCI_BASE + 0x04)) 945 #define MCI_SD *((volatile unsigned long *)(SD_MCI_BASE + 0x04))
923 946
924 mutex_lock(&sd_mtx); 947 mutex_lock(&sd_mtx);
925 enable_controller(true); /* must be on to read regs */ 948
949 for (int i = 0; i < NUM_DRIVES ; i++)
950 enable_controller(true, i); /* must be on to read regs */
951
926 info->mci_nand = MCI_NAND; 952 info->mci_nand = MCI_NAND;
927#ifdef HAVE_MULTIDRIVE 953#ifdef HAVE_MULTIDRIVE
928 info->mci_sd = MCI_SD; 954 info->mci_sd = MCI_SD;
929#endif 955#endif
930 enable_controller(false); 956
957 for (int i = 0; i < NUM_DRIVES ; i++)
958 enable_controller(false, i);
959
931 mutex_unlock(&sd_mtx); 960 mutex_unlock(&sd_mtx);
932} 961}
933 962
@@ -948,10 +977,10 @@ int sd_event(long id, intptr_t data)
948 977
949 if (id == SYS_HOTSWAP_INSERTED) 978 if (id == SYS_HOTSWAP_INSERTED)
950 { 979 {
951 enable_controller(true); 980 enable_controller(true, data);
952 init_pl180_controller(data); 981 init_pl180_controller(data);
953 rc = sd_init_card(data); 982 rc = sd_init_card(data);
954 enable_controller(false); 983 enable_controller(false, data);
955 } 984 }
956 985
957 mutex_unlock(&sd_mtx); 986 mutex_unlock(&sd_mtx);
@@ -968,3 +997,42 @@ int sd_event(long id, intptr_t data)
968 997
969 return rc; 998 return rc;
970} 999}
1000
1001#if defined(CONFIG_POWER_SAVING) && (CONFIG_POWER_SAVING & POWERSV_DISK)
1002/* declared in system-as3525.c */
1003void ams_sd_set_low_speed(bool slow)
1004{
1005 /* block access while speed is changed */
1006 mutex_lock(&sd_mtx);
1007 enable_controller(true, INTERNAL_AS3525);
1008
1009 /* After a data write, data cannot be written to MCI_CLOCK
1010 for 3 MCLK periods + 2 PCLK periods. ~10us worst case
1011 */
1012 udelay(100);
1013 if (slow)
1014 {
1015 /* only affects internal drive clock speed*/
1016 CGU_IDE = (CGU_IDE & ~(0xF << 2)) | (AS3525_IDE_DIV_MAX << 2);
1017 /* power save is enabled for the sd card(s) */
1018 for (int i = 0; i < NUM_DRIVES ; i++)
1019 {
1020 if (i != INTERNAL_AS3525 && (MCI_CLOCK(i) & MCI_CLOCK_POWERSAVE) == 0)
1021 MCI_CLOCK(i) |= MCI_CLOCK_POWERSAVE;
1022 }
1023 }
1024 else
1025 {
1026 /* Full Speed */
1027 CGU_IDE = (CGU_IDE & ~(0xF << 2)) | (AS3525_IDE_DIV << 2);
1028 for (int i = 0; i < NUM_DRIVES ; i++)
1029 {
1030 if (i != INTERNAL_AS3525 && (MCI_CLOCK(i) & MCI_CLOCK_POWERSAVE) != 0)
1031 MCI_CLOCK(i) = (MCI_CLOCK(i) & ~MCI_CLOCK_POWERSAVE);
1032 }
1033 }
1034 enable_controller(false, INTERNAL_AS3525);
1035 mutex_unlock(&sd_mtx);
1036}
1037#endif
1038
diff --git a/firmware/target/arm/as3525/sd-as3525v2.c b/firmware/target/arm/as3525/sd-as3525v2.c
index b512cc2ea4..d27df5289c 100644
--- a/firmware/target/arm/as3525/sd-as3525v2.c
+++ b/firmware/target/arm/as3525/sd-as3525v2.c
@@ -488,7 +488,7 @@ static int sd_init_card(const int drive)
488 card_info[drive].initialized = 0; 488 card_info[drive].initialized = 0;
489 card_info[drive].rca = 0; 489 card_info[drive].rca = 0;
490 490
491 /* assume 24 MHz clock / 60 = 400 kHz */ 491 /* assume 24 MHz clock / (2x)60 = 200 kHz */
492 MCI_CLKDIV = (MCI_CLKDIV & ~(0xFF)) | 0x3C; /* CLK_DIV_0 : bits 7:0 */ 492 MCI_CLKDIV = (MCI_CLKDIV & ~(0xFF)) | 0x3C; /* CLK_DIV_0 : bits 7:0 */
493 493
494 /* 100 - 400kHz clock required for Identification Mode */ 494 /* 100 - 400kHz clock required for Identification Mode */
@@ -957,3 +957,27 @@ int sd_event(long id, intptr_t data)
957 957
958 return rc; 958 return rc;
959} 959}
960
961#if defined(CONFIG_POWER_SAVING) && (CONFIG_POWER_SAVING & POWERSV_DISK)
962/* declared in system-as3525.c */
963void ams_sd_set_low_speed(bool slow)
964{
965 /* block access while speed is changed */
966 mutex_lock(&sd_mtx);
967 enable_controller(true);
968 if (slow)
969 {
970 CGU_SDSLOT = (CGU_SDSLOT & ~(0xF << 2)) | (AS3525_SDSLOT_DIV_MAX << 2);
971 /* power save is enabled for the sd card(s) ASSUMES CRD0 is int drive! */
972 MCI_CLKENA |= (CCLK_LP_CRD1 | CCLK_LP_CRD2 | CCLK_LP_CRD3);
973 }
974 else
975 {
976 /* Full Speed */
977 CGU_SDSLOT = (CGU_SDSLOT & ~(0xF << 2)) | (AS3525_SDSLOT_DIV << 2);
978 MCI_CLKENA = (MCI_CLKENA & ~(CCLK_LP_CRD1 | CCLK_LP_CRD2 | CCLK_LP_CRD3));
979 }
980 enable_controller(false);
981 mutex_unlock(&sd_mtx);
982}
983#endif
diff --git a/firmware/target/arm/as3525/system-as3525.c b/firmware/target/arm/as3525/system-as3525.c
index d630ef38ec..c11c90f9f3 100644
--- a/firmware/target/arm/as3525/system-as3525.c
+++ b/firmware/target/arm/as3525/system-as3525.c
@@ -52,6 +52,29 @@ struct mutex cpufreq_mtx;
52#define default_interrupt(name) \ 52#define default_interrupt(name) \
53 extern __attribute__((weak,alias("UIRQ"))) void name (void) 53 extern __attribute__((weak,alias("UIRQ"))) void name (void)
54 54
55#ifdef CONFIG_POWER_SAVING
56/* Powersave functions either manipulate the system directly
57 or pass enabled flag on to these specific functions
58 dis/enabling powersaving for the selected subsystem
59*/
60#if (CONFIG_POWER_SAVING & POWERSV_CPU)
61/*cpu_set_powersave*/
62#include "settings.h"
63#endif
64#if (CONFIG_POWER_SAVING & POWERSV_DISP)
65/*disp_set_powersave*/
66void ams_ssp_set_low_speed(bool slow); /*lcd-clip-plus.c & lcd-clipzip.c*/
67#endif
68#if (CONFIG_POWER_SAVING & POWERSV_DISK)
69/*disk_set_powersave*/
70void ams_sd_set_low_speed(bool slow); /* sd-as3525.c & sd-as3525v2.c */
71#endif
72#if (CONFIG_POWER_SAVING & POWERSV_I2C)
73/*i2c_set_powersave*/
74void ams_i2c_set_low_speed(bool slow); /* ascodec-as3525.c*/
75#endif
76#endif /*CONFIG_POWER_SAVING*/
77
55#if CONFIG_USBOTG != USBOTG_DESIGNWARE 78#if CONFIG_USBOTG != USBOTG_DESIGNWARE
56static void UIRQ (void) __attribute__((interrupt ("IRQ"))); 79static void UIRQ (void) __attribute__((interrupt ("IRQ")));
57#endif 80#endif
@@ -422,6 +445,39 @@ void udelay(unsigned usecs)
422 ); 445 );
423} 446}
424 447
448#ifdef CONFIG_POWER_SAVING
449#if (CONFIG_POWER_SAVING & POWERSV_CPU)
450void cpu_set_powersave(bool enabled)
451{
452 /*global_settings.cpu_powersave*/
453 /*handled in: set_cpu_frequency()*/
454 (void) enabled;
455}
456#endif
457#if (CONFIG_POWER_SAVING & POWERSV_DISK)
458void disk_set_powersave(bool enabled)
459{
460 /*global_settings.disk_powersave*/
461 ams_sd_set_low_speed(enabled);
462}
463#endif
464#if (CONFIG_POWER_SAVING & POWERSV_DISP)
465void disp_set_powersave(bool enabled)
466{
467 /*global_settings.disp_powersave*/
468 ams_ssp_set_low_speed(enabled);
469}
470#endif
471#if (CONFIG_POWER_SAVING & POWERSV_I2C)
472void i2c_set_powersave(bool enabled)
473{
474 /*global_settings.i2c_powersave*/
475 ams_i2c_set_low_speed(enabled);
476}
477#endif
478#endif /*defined(CONFIG_POWER_SAVING)*/
479
480
425#ifndef BOOTLOADER 481#ifndef BOOTLOADER
426#ifdef HAVE_ADJUSTABLE_CPU_FREQ 482#ifdef HAVE_ADJUSTABLE_CPU_FREQ
427bool set_cpu_frequency__lock(void) 483bool set_cpu_frequency__lock(void)
@@ -481,7 +537,12 @@ void set_cpu_frequency(long frequency)
481 CGU_PROC = ((0xf << 4) | (0x3 << 2) | AS3525_CLK_MAIN); 537 CGU_PROC = ((0xf << 4) | (0x3 << 2) | AS3525_CLK_MAIN);
482 538
483#ifdef HAVE_ADJUSTABLE_CPU_VOLTAGE 539#ifdef HAVE_ADJUSTABLE_CPU_VOLTAGE
484 /* Decreasing frequency so reduce voltage after change */ 540 /* Decreasing frequency so reduce voltage after change */
541#if defined(CONFIG_POWER_SAVING) && (CONFIG_POWER_SAVING & POWERSV_CPU)
542 if (!global_settings.cpu_powersave)
543 ascodec_write(AS3514_CVDD_DCDC3, (AS314_CP_DCDC3_SETTING | CVDD_1_15));
544 else
545#endif
485 ascodec_write(AS3514_CVDD_DCDC3, (AS314_CP_DCDC3_SETTING | CVDD_1_10)); 546 ascodec_write(AS3514_CVDD_DCDC3, (AS314_CP_DCDC3_SETTING | CVDD_1_10));
486#endif /* HAVE_ADJUSTABLE_CPU_VOLTAGE */ 547#endif /* HAVE_ADJUSTABLE_CPU_VOLTAGE */
487 548
@@ -519,6 +580,13 @@ void set_cpu_frequency(long frequency)
519 580
520 /* Set CVDD1 power supply */ 581 /* Set CVDD1 power supply */
521#ifdef HAVE_ADJUSTABLE_CPU_VOLTAGE 582#ifdef HAVE_ADJUSTABLE_CPU_VOLTAGE
583#if defined(CONFIG_POWER_SAVING) && (CONFIG_POWER_SAVING & POWERSV_CPU)
584 if (!global_settings.cpu_powersave)
585 {
586 ascodec_write_pmu(0x17, 1, 0x80 | 26);
587 return;
588 }
589#endif
522#if defined(SANSA_CLIPZIP) 590#if defined(SANSA_CLIPZIP)
523 ascodec_write_pmu(0x17, 1, 0x80 | 20); 591 ascodec_write_pmu(0x17, 1, 0x80 | 20);
524#elif defined(SANSA_CLIPPLUS) 592#elif defined(SANSA_CLIPPLUS)
diff --git a/firmware/target/arm/as3525/system-target.h b/firmware/target/arm/as3525/system-target.h
index 5cdc573a1b..9c5b5a9cd6 100644
--- a/firmware/target/arm/as3525/system-target.h
+++ b/firmware/target/arm/as3525/system-target.h
@@ -73,6 +73,26 @@ static inline void mdelay(unsigned msecs)
73void usb_insert_int(void); 73void usb_insert_int(void);
74void usb_remove_int(void); 74void usb_remove_int(void);
75 75
76
77#ifdef CONFIG_POWER_SAVING
78/* Powersave functions either manipulate the system directly
79 or pass enabled flag on to the devices specific function
80 dis/enabling powersaving for the selected subsystem
81*/
82#if (CONFIG_POWER_SAVING & POWERSV_CPU)
83void cpu_set_powersave(bool enabled);
84#endif
85#if (CONFIG_POWER_SAVING & POWERSV_DISP)
86void disp_set_powersave(bool enabled);
87#endif
88#if (CONFIG_POWER_SAVING & POWERSV_DISK)
89void disk_set_powersave(bool enabled);
90#endif
91#if (CONFIG_POWER_SAVING & POWERSV_I2C)
92void i2c_set_powersave(bool enabled);
93#endif
94#endif /*CONFIG_POWER_SAVING*/
95
76#ifdef HAVE_ADJUSTABLE_CPU_FREQ 96#ifdef HAVE_ADJUSTABLE_CPU_FREQ
77#define CPU_BOOST_LOCK_DEFINED 97#define CPU_BOOST_LOCK_DEFINED
78 98
diff --git a/manual/configure_rockbox/system_options.tex b/manual/configure_rockbox/system_options.tex
index ff2967cec7..b279308e71 100755
--- a/manual/configure_rockbox/system_options.tex
+++ b/manual/configure_rockbox/system_options.tex
@@ -297,6 +297,30 @@ therefore result in better runtime.
297 \end{description} 297 \end{description}
298} %\nopt{HAS_BUTTON_HOLD} 298} %\nopt{HAS_BUTTON_HOLD}
299 299
300\opt{CONFIG_POWER_SAVING}{
301 \subsection{Power Saving}
302 These options allow users to increase runtime by lowering performance
303 of select subsystems. Certain options may \emph{not} be applicable to your
304 \dap{} or may cause undesired operation to your particular use case.
305
306 \emph{WARNING!} While every effort has been made to ensure the safety of these
307 options, due to manufacturing variance some options may cause unwanted side
308 effects, cause the \dap{} to crash or (while unlikely) even \emph{destroy}
309 your \dap{}. \emph{PROCEED WITH CAUTION}
310
311 \begin{description}
312
313 \item[CPU]
314 Allows lower voltages or cpu speed when enabled.
315 \item[Disk]
316 Allows slower disk operations when enabled.
317 \item[I2C]
318 Allows slower clocking of I2C device bus when enabled.
319 \item[Display]
320 Allows slower screen refresh rates when enabled.
321
322 \end{description}
323} %\opt{CONFIG_POWER_SAVING}
300 324
301\opt{usb_hid}{ 325\opt{usb_hid}{
302 \subsection{\label{ref:USB_HID}USB HID} 326 \subsection{\label{ref:USB_HID}USB HID}