Arndale: save power by default (Fix #774)

* Use regulator interface in eMMC driver to enable its clock
This commit is contained in:
Stefan Kalkowski 2013-06-20 16:00:24 +02:00 committed by Norman Feske
parent cc0f4bc9d2
commit a4eb4bfa07
6 changed files with 211 additions and 60 deletions

View File

@ -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" },
};

View File

@ -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 {
<any-service> <parent/> <any-child/> </any-service>
</default-route>
<start name="platform_drv">
<resource name="RAM" quantum="1M"/>
<provides><service name="Regulator"/></provides>
</start>
<start name="timer">
<resource name="RAM" quantum="1M"/>
<provides><service name="Timer"/></provides>
@ -61,6 +66,7 @@ install_config $config
set boot_modules {
core init
timer
platform_drv
sd_card_drv
test-block
}

View File

@ -47,6 +47,7 @@ class Cmu : public Regulator::Driver,
struct P : Register<OFF, 32>::template Bitfield < 8, 6> { };
struct M : Register<OFF, 32>::template Bitfield <16, 10> { };
struct Locked : Register<OFF, 32>::template Bitfield <29, 1> { };
struct Enable : Register<OFF, 32>::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<Clk_src_mask_fsys::Sata_mask>(1);
}
void _sata_disable()
{
/* disable I2C for SATA */
write<Clk_gate_ip_fsys::Sata_phy_i2c>(0);
/* disable SATA and SATA Phy */
write<Clk_gate_ip_fsys::Sata>(0);
write<Clk_gate_ip_fsys::Sata_phy_ctrl>(0);
write<Clk_src_mask_fsys::Sata_mask>(0);
}
bool _sata_enabled()
{
return read<Clk_gate_ip_fsys::Sata>() &&
read<Clk_gate_ip_fsys::Sata_phy_ctrl>() &&
read<Clk_src_mask_fsys::Sata_mask>();
}
/***********************
** 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<Clk_div_fsys0::Usbdrd30_ratio>(11); /* */
write<Clk_div_fsys0::Usbdrd30_ratio>(11);
while (read<Clk_div_stat_fsys0::Div_usbdrd30>()) ;
/* enable USBDRD30 clock */
@ -299,16 +316,44 @@ class Cmu : public Regulator::Driver,
write<Clk_src_mask_fsys::Usbdrd30_mask>(1);
}
void _usb30_disable()
void _enable(Regulator_id id)
{
write<Clk_gate_ip_fsys::Usbdrd30>(0);
write<Clk_src_mask_fsys::Usbdrd30_mask>(0);
switch (id) {
case CLK_SATA:
_sata_enable();
break;
case CLK_USB30:
_usb30_enable();
break;
case CLK_MMC0:
write<Clk_gate_ip_fsys::Clk_sdmmc0>(1);
write<Clk_src_mask_fsys::Mmc0_mask>(1);
break;
default:
PWRN("Unsupported for %s", names[id].name);
}
}
bool _usb30_enabled()
void _disable(Regulator_id id)
{
return read<Clk_gate_ip_fsys::Usbdrd30>() &&
read<Clk_src_mask_fsys::Usbdrd30_mask>();
switch (id) {
case CLK_SATA:
write<Clk_gate_ip_fsys::Sata_phy_i2c>(0);
write<Clk_gate_ip_fsys::Sata>(0);
write<Clk_gate_ip_fsys::Sata_phy_ctrl>(0);
write<Clk_src_mask_fsys::Sata_mask>(0);
break;
case CLK_USB30:
write<Clk_gate_ip_fsys::Usbdrd30>(0);
write<Clk_src_mask_fsys::Usbdrd30_mask>(0);
break;
case CLK_MMC0:
write<Clk_gate_ip_fsys::Clk_sdmmc0>(0);
write<Clk_src_mask_fsys::Mmc0_mask>(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<Clk_gate_ip_acp>(0);
write<Clk_gate_ip_isp0>(0);
write<Clk_gate_ip_isp1>(0);
write<Clk_gate_sclk_isp>(0);
write<Clk_gate_ip_gscl>(0);
write<Clk_gate_ip_disp1>(0);
write<Clk_gate_ip_mfc>(0);
write<Clk_gate_ip_g3d>(0);
write<Clk_gate_ip_gen>(0);
write<Clk_gate_ip_fsys>(0);
write<Clk_gate_ip_peric>(Clk_gate_ip_peric::Clk_uart2::bits(1) |
Clk_gate_ip_peric::Clk_pwm::bits(1));
write<Clk_gate_block>(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>(Pll_div2_sel::Mpll_fout_sel::MPLL_FOUT_HALF);
write<Clk_src_core1::Mux_mpll_sel>(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<Clk_gate_ip_fsys::Sata>() &&
read<Clk_gate_ip_fsys::Sata_phy_ctrl>() &&
read<Clk_src_mask_fsys::Sata_mask>();
case CLK_USB30:
return _usb30_enabled();
return read<Clk_gate_ip_fsys::Usbdrd30>() &&
read<Clk_src_mask_fsys::Usbdrd30_mask>();
case CLK_MMC0:
return read<Clk_gate_ip_fsys::Clk_sdmmc0>() &&
read<Clk_src_mask_fsys::Mmc0_mask>();
default:
PWRN("Unsupported for %s", names[id].name);
}

View File

@ -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:

View File

@ -27,16 +27,77 @@ class Pmu : public Regulator::Driver,
{
private:
template <unsigned OFF>
struct Control : Register <OFF, 32>
template <unsigned OFFSET>
struct Control : Register <OFFSET, 32>
{
struct Enable : Register<OFF, 32>::template Bitfield<0, 1> { };
struct Enable : Register<OFFSET, 32>::template Bitfield<0, 1> { };
};
template <unsigned OFFSET>
struct Configuration : Register <OFFSET, 32>
{
struct Local_pwr_cfg : Register<OFFSET, 32>::template Bitfield<0, 3> { };
};
template <unsigned OFFSET>
struct Status : Register <OFFSET, 32>
{
struct Stat : Register<OFFSET, 32>::template Bitfield<0, 3> { };
};
template <unsigned OFFSET>
struct Sysclk_configuration : Register <OFFSET, 32>
{
struct Local_pwr_cfg : Register<OFFSET, 32>::template Bitfield<0, 1> { };
};
template <unsigned OFFSET>
struct Sysclk_status : Register <OFFSET, 32>
{
struct Stat : Register<OFFSET, 32>::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 <typename C, typename S>
void _disable_domain()
{
if (read<typename S::Stat>() == 0)
return;
write<typename C::Local_pwr_cfg>(0);
while (read<typename S::Stat>() != 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<Hdmi_phy_control ::Enable>(0);
write<Usbdrd_phy_control ::Enable>(0);
write<Usbhost_phy_control::Enable>(0);
write<Efnand_phy_control ::Enable>(0);
write<Adc_phy_control ::Enable>(0);
write<Mtcadc_phy_control ::Enable>(0);
write<Dptx_phy_control ::Enable>(0);
write<Sata_phy_control ::Enable>(0);
_disable_domain<Gscl_configuration, Gscl_status>();
_disable_domain<Isp_configuration, Isp_status>();
_disable_domain<Mfc_configuration, Mfc_status>();
_disable_domain<G3d_configuration, G3d_status>();
_disable_domain<Disp1_configuration, Disp1_status>();
_disable_domain<Mau_configuration, Mau_status>();
_disable_domain<Vpll_sysclk_configuration, Vpll_sysclk_status>();
_disable_domain<Epll_sysclk_configuration, Epll_sysclk_status>();
_disable_domain<Cpll_sysclk_configuration, Cpll_sysclk_status>();
_disable_domain<Gpll_sysclk_configuration, Gpll_sysclk_status>();
}
/********************************

View File

@ -15,6 +15,7 @@
#include <base/sleep.h>
#include <base/printf.h>
#include <cap_session/connection.h>
#include <regulator_session/connection.h>
/* local includes */
#include <driver.h>
@ -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));