From a4eb4bfa078d15005c77aab911ed010b0cb1d72f Mon Sep 17 00:00:00 2001 From: Stefan Kalkowski Date: Thu, 20 Jun 2013 16:00:24 +0200 Subject: [PATCH] Arndale: save power by default (Fix #774) * Use regulator interface in eMMC driver to enable its clock --- .../platform/arndale/regulator/consts.h | 2 + os/run/sd_card.run | 6 + os/src/drivers/platform/arndale/cmu.h | 167 ++++++++++++------ os/src/drivers/platform/arndale/main.cc | 1 + os/src/drivers/platform/arndale/pmu.h | 91 +++++++++- os/src/drivers/sd_card/exynos5/main.cc | 4 +- 6 files changed, 211 insertions(+), 60 deletions(-) diff --git a/os/include/platform/arndale/regulator/consts.h b/os/include/platform/arndale/regulator/consts.h index 480771139..703256b06 100644 --- a/os/include/platform/arndale/regulator/consts.h +++ b/os/include/platform/arndale/regulator/consts.h @@ -22,6 +22,7 @@ namespace Regulator { CLK_CPU, CLK_SATA, CLK_USB30, + CLK_MMC0, PWR_SATA, PWR_USB30, MAX, @@ -37,6 +38,7 @@ namespace Regulator { { CLK_CPU, "clock-cpu" }, { CLK_SATA, "clock-sata" }, { CLK_USB30, "clock-usb3.0" }, + { CLK_MMC0, "clock-mmc0" }, { PWR_SATA, "power-sata" }, { PWR_USB30, "power-usb3.0" }, }; diff --git a/os/run/sd_card.run b/os/run/sd_card.run index 762cb764d..2a58a6849 100644 --- a/os/run/sd_card.run +++ b/os/run/sd_card.run @@ -5,6 +5,7 @@ # generic components set build_components { core init + drivers/platform drivers/timer drivers/sd_card test/block @@ -36,6 +37,10 @@ set config { + + + + @@ -61,6 +66,7 @@ install_config $config set boot_modules { core init timer + platform_drv sd_card_drv test-block } diff --git a/os/src/drivers/platform/arndale/cmu.h b/os/src/drivers/platform/arndale/cmu.h index a6ad0cffa..0f1276590 100644 --- a/os/src/drivers/platform/arndale/cmu.h +++ b/os/src/drivers/platform/arndale/cmu.h @@ -47,6 +47,7 @@ class Cmu : public Regulator::Driver, struct P : Register::template Bitfield < 8, 6> { }; struct M : Register::template Bitfield <16, 10> { }; struct Locked : Register::template Bitfield <29, 1> { }; + struct Enable : Register::template Bitfield <31, 1> { }; }; @@ -121,6 +122,11 @@ class Cmu : public Regulator::Driver, } }; + + /************************ + ** CMU CORE registers ** + ************************/ + typedef Pll_lock<0x4000> Mpll_lock; typedef Pll_con0<0x4100> Mpll_con0; @@ -129,11 +135,25 @@ class Cmu : public Regulator::Driver, struct Mux_mpll_sel : Bitfield<8, 1> { enum { XXTI, MPLL_FOUT_RGT }; }; }; + struct Clk_gate_ip_acp : Register<0x8800, 32> { }; + struct Clk_gate_ip_isp0 : Register<0xc800, 32> { }; + struct Clk_gate_ip_isp1 : Register<0xc804, 32> { }; + struct Clk_gate_sclk_isp : Register<0xc900, 32> { }; + /*********************** ** CMU TOP registers ** ***********************/ + typedef Pll_lock<0x10020> Cpll_lock; + typedef Pll_lock<0x10030> Epll_lock; + typedef Pll_lock<0x10040> Vpll_lock; + typedef Pll_lock<0x10050> Gpll_lock; + typedef Pll_con0<0x10120> Cpll_con0; + typedef Pll_con0<0x10130> Epll_con0; + typedef Pll_con0<0x10140> Vpll_con0; + typedef Pll_con0<0x10150> Gpll_con0; + struct Clk_src_top2 : Register<0x10218, 32> { struct Mux_mpll_user_sel : Bitfield<20, 1> { enum { XXTI, MOUT_MPLL}; }; @@ -149,6 +169,7 @@ class Cmu : public Regulator::Driver, struct Clk_src_mask_fsys : Register<0x10340, 32> { + struct Mmc0_mask : Bitfield<0, 1> { enum { MASK, UNMASK }; }; struct Sata_mask : Bitfield<24, 1> { enum { MASK, UNMASK }; }; struct Usbdrd30_mask : Bitfield<28, 1> { enum { MASK, UNMASK }; }; }; @@ -165,16 +186,35 @@ class Cmu : public Regulator::Driver, struct Div_usbdrd30 : Bitfield<24, 1> {}; }; + struct Clk_gate_ip_gscl : Register<0x10920, 32> { }; + struct Clk_gate_ip_disp1 : Register<0x10928, 32> { }; + struct Clk_gate_ip_mfc : Register<0x1092c, 32> { }; + struct Clk_gate_ip_g3d : Register<0x10930, 32> { }; + struct Clk_gate_ip_gen : Register<0x10934, 32> { }; + struct Clk_gate_ip_fsys : Register<0x10944, 32> { struct Pdma0 : Bitfield<1, 1> { }; struct Pdma1 : Bitfield<2, 1> { }; struct Sata : Bitfield<6, 1> { }; - struct Usbdrd30 : Bitfield<19, 0> { }; + struct Clk_sdmmc0 : Bitfield<12, 1> { }; + struct Clk_usbhost20 : Bitfield<18, 1> { }; + struct Usbdrd30 : Bitfield<19, 1> { }; struct Sata_phy_ctrl : Bitfield<24, 1> { }; struct Sata_phy_i2c : Bitfield<25, 1> { }; }; + struct Clk_gate_ip_peric : Register<0x10950, 32> + { + struct Clk_uart2 : Bitfield<2, 1> { }; + struct Clk_pwm : Bitfield<24, 1> { }; + }; + + struct Clk_gate_block : Register<0x10980, 32> + { + struct Clk_gen : Bitfield<2, 1> { }; + }; + /************************* ** CMU CDREX registers ** @@ -240,9 +280,9 @@ class Cmu : public Regulator::Driver, } - /******************** - ** SATA functions ** - ********************/ + /********************** + ** Device functions ** + **********************/ void _sata_enable() { @@ -262,36 +302,13 @@ class Cmu : public Regulator::Driver, write(1); } - void _sata_disable() - { - /* disable I2C for SATA */ - write(0); - - /* disable SATA and SATA Phy */ - write(0); - write(0); - write(0); - } - - bool _sata_enabled() - { - return read() && - read() && - read(); - } - - - /*********************** - ** USB 3.0 functions ** - ***********************/ - void _usb30_enable() { /** * set USBDRD30 clock to 66 MHz * assuming 800 MHz from sclk_mpll_user, formula: sclk / (divider + 1) */ - write(11); /* */ + write(11); while (read()) ; /* enable USBDRD30 clock */ @@ -299,16 +316,44 @@ class Cmu : public Regulator::Driver, write(1); } - void _usb30_disable() + void _enable(Regulator_id id) { - write(0); - write(0); + switch (id) { + case CLK_SATA: + _sata_enable(); + break; + case CLK_USB30: + _usb30_enable(); + break; + case CLK_MMC0: + write(1); + write(1); + break; + default: + PWRN("Unsupported for %s", names[id].name); + } } - bool _usb30_enabled() + void _disable(Regulator_id id) { - return read() && - read(); + switch (id) { + case CLK_SATA: + write(0); + write(0); + write(0); + write(0); + break; + case CLK_USB30: + write(0); + write(0); + break; + case CLK_MMC0: + write(0); + write(0); + break; + default: + PWRN("Unsupported for %s", names[id].name); + } } public: @@ -321,13 +366,31 @@ class Cmu : public Regulator::Driver, Genode::Board_base::CMU_MMIO_SIZE), _cpu_freq(CPU_FREQ_1600) { - _sata_disable(); - _usb30_disable(); + /** + * Close certain clock gates by default (~ 0.7 Watt reduction) + */ + write(0); + write(0); + write(0); + write(0); + write(0); + write(0); + write(0); + write(0); + write(0); + write(0); + write(Clk_gate_ip_peric::Clk_uart2::bits(1) | + Clk_gate_ip_peric::Clk_pwm::bits(1)); + write(Clk_gate_block::Clk_gen::bits(1)); + + /** + * Set default CPU frequency + */ _cpu_clk_freq(_cpu_freq); /** - * Hard wiring of reference clocks + * Hard wiring of certain reference clocks */ write(Pll_div2_sel::Mpll_fout_sel::MPLL_FOUT_HALF); write(Clk_src_core1::Mux_mpll_sel::MPLL_FOUT_RGT); @@ -372,31 +435,25 @@ class Cmu : public Regulator::Driver, void set_state(Regulator_id id, bool enable) { - switch (id) { - case CLK_SATA: - if (enable) - _sata_enable(); - else - _sata_disable(); - break; - case CLK_USB30: - if (enable) - _usb30_enable(); - else - _usb30_disable(); - break; - default: - PWRN("Unsupported for %s", names[id].name); - } + if (enable) + _enable(id); + else + _disable(id); } bool state(Regulator_id id) { switch (id) { case CLK_SATA: - return _sata_enabled(); + return read() && + read() && + read(); case CLK_USB30: - return _usb30_enabled(); + return read() && + read(); + case CLK_MMC0: + return read() && + read(); default: PWRN("Unsupported for %s", names[id].name); } diff --git a/os/src/drivers/platform/arndale/main.cc b/os/src/drivers/platform/arndale/main.cc index c9ffc2054..422612ffa 100644 --- a/os/src/drivers/platform/arndale/main.cc +++ b/os/src/drivers/platform/arndale/main.cc @@ -31,6 +31,7 @@ struct Driver_factory : Regulator::Driver_factory case Regulator::CLK_CPU: case Regulator::CLK_SATA: case Regulator::CLK_USB30: + case Regulator::CLK_MMC0: return _cmu; case Regulator::PWR_SATA: case Regulator::PWR_USB30: diff --git a/os/src/drivers/platform/arndale/pmu.h b/os/src/drivers/platform/arndale/pmu.h index 1e6ce7ef6..1aa38a15e 100644 --- a/os/src/drivers/platform/arndale/pmu.h +++ b/os/src/drivers/platform/arndale/pmu.h @@ -27,16 +27,77 @@ class Pmu : public Regulator::Driver, { private: - template - struct Control : Register + template + struct Control : Register { - struct Enable : Register::template Bitfield<0, 1> { }; + struct Enable : Register::template Bitfield<0, 1> { }; }; + template + struct Configuration : Register + { + struct Local_pwr_cfg : Register::template Bitfield<0, 3> { }; + }; + + template + struct Status : Register + { + struct Stat : Register::template Bitfield<0, 3> { }; + }; + + template + struct Sysclk_configuration : Register + { + struct Local_pwr_cfg : Register::template Bitfield<0, 1> { }; + }; + + template + struct Sysclk_status : Register + { + struct Stat : Register::template Bitfield<0, 1> { }; + }; + + typedef Control<0x700> Hdmi_phy_control; typedef Control<0x704> Usbdrd_phy_control; typedef Control<0x708> Usbhost_phy_control; + typedef Control<0x70c> Efnand_phy_control; + typedef Control<0x718> Adc_phy_control; + typedef Control<0x71c> Mtcadc_phy_control; + typedef Control<0x720> Dptx_phy_control; typedef Control<0x724> Sata_phy_control; + typedef Sysclk_configuration<0x2a40> Vpll_sysclk_configuration; + typedef Sysclk_status<0x2a44> Vpll_sysclk_status; + typedef Sysclk_configuration<0x2a60> Epll_sysclk_configuration; + typedef Sysclk_status<0x2a64> Epll_sysclk_status; + typedef Sysclk_configuration<0x2aa0> Cpll_sysclk_configuration; + typedef Sysclk_status<0x2aa4> Cpll_sysclk_status; + typedef Sysclk_configuration<0x2ac0> Gpll_sysclk_configuration; + typedef Sysclk_status<0x2ac4> Gpll_sysclk_status; + + typedef Configuration<0x4000> Gscl_configuration; + typedef Status<0x4004> Gscl_status; + typedef Configuration<0x4020> Isp_configuration; + typedef Status<0x4024> Isp_status; + typedef Configuration<0x4040> Mfc_configuration; + typedef Status<0x4044> Mfc_status; + typedef Configuration<0x4060> G3d_configuration; + typedef Status<0x4064> G3d_status; + typedef Configuration<0x40A0> Disp1_configuration; + typedef Status<0x40A4> Disp1_status; + typedef Configuration<0x40C0> Mau_configuration; + typedef Status<0x40C4> Mau_status; + + + template + void _disable_domain() + { + if (read() == 0) + return; + write(0); + while (read() != 0) ; + } + /*********************** ** USB 3.0 functions ** @@ -67,7 +128,29 @@ class Pmu : public Regulator::Driver, * Constructor */ Pmu() : Genode::Attached_mmio(Genode::Board_base::PMU_MMIO_BASE, - Genode::Board_base::PMU_MMIO_SIZE) { } + Genode::Board_base::PMU_MMIO_SIZE) + { + write(0); + write(0); + write(0); + write(0); + write(0); + write(0); + write(0); + write(0); + + _disable_domain(); + _disable_domain(); + _disable_domain(); + _disable_domain(); + _disable_domain(); + _disable_domain(); + + _disable_domain(); + _disable_domain(); + _disable_domain(); + _disable_domain(); + } /******************************** diff --git a/os/src/drivers/sd_card/exynos5/main.cc b/os/src/drivers/sd_card/exynos5/main.cc index 7ee8145c1..641ed560d 100644 --- a/os/src/drivers/sd_card/exynos5/main.cc +++ b/os/src/drivers/sd_card/exynos5/main.cc @@ -15,6 +15,7 @@ #include #include #include +#include /* local includes */ #include @@ -48,7 +49,8 @@ int main(int argc, char **argv) enum { STACK_SIZE = 8192 }; static Cap_connection cap; static Rpc_entrypoint ep(&cap, STACK_SIZE, "block_ep"); - + static Regulator::Connection mmc0_regulator(Regulator::CLK_MMC0); + mmc0_regulator.set_state(true); static Block::Root block_root(&ep, env()->heap(), driver_factory); env()->parent()->announce(ep.manage(&block_root));