mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-31 08:25:38 +00:00
Implement cpu frequency scaling for Arndale
* Implements platform driver for Arndale providing Regulator for CPU clock * Implements a cpu frequency scaling test using the affinity test * Fixes #770
This commit is contained in:
parent
8fb8cf1c8b
commit
1d34589f84
@ -31,6 +31,9 @@ namespace Genode
|
||||
MMIO_0_BASE = 0x10000000,
|
||||
MMIO_0_SIZE = 0x10000000,
|
||||
|
||||
CMU_MMIO_BASE = 0x10010000,
|
||||
CMU_MMIO_SIZE = 0x21000,
|
||||
|
||||
/* interrupt controller */
|
||||
GIC_CPU_MMIO_BASE = 0x10480000,
|
||||
GIC_CPU_MMIO_SIZE = 0x00010000,
|
||||
|
68
os/include/platform/arndale/regulator/consts.h
Normal file
68
os/include/platform/arndale/regulator/consts.h
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* \brief Regulator definitions for Arndale
|
||||
* \author Stefan Kalkowski <stefan.kalkowski@genode-labs.com>
|
||||
* \date 2013-06-13
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE__PLATFORM__ARNDALE__REGULATOR__CONSTS_H_
|
||||
#define _INCLUDE__PLATFORM__ARNDALE__REGULATOR__CONSTS_H_
|
||||
|
||||
#include <util/string.h>
|
||||
|
||||
namespace Regulator {
|
||||
|
||||
enum Regulator_id {
|
||||
CLK_CPU,
|
||||
MAX,
|
||||
INVALID
|
||||
};
|
||||
|
||||
struct Regulator_name {
|
||||
Regulator_id id;
|
||||
const char * name;
|
||||
};
|
||||
|
||||
Regulator_name names[] = {
|
||||
{ CLK_CPU, "clock-cpu" },
|
||||
};
|
||||
|
||||
Regulator_id regulator_id_by_name(const char * name)
|
||||
{
|
||||
for (unsigned i = 0; i < MAX; i++)
|
||||
if (Genode::strcmp(names[i].name, name) == 0)
|
||||
return names[i].id;
|
||||
return INVALID;
|
||||
}
|
||||
|
||||
const char * regulator_name_by_id(Regulator_id id) {
|
||||
return (id < MAX) ? names[id].name : 0; }
|
||||
|
||||
|
||||
/***************************************
|
||||
** Device specific level definitions **
|
||||
***************************************/
|
||||
|
||||
enum Cpu_clock_freq {
|
||||
CPU_FREQ_200,
|
||||
CPU_FREQ_400,
|
||||
CPU_FREQ_600,
|
||||
CPU_FREQ_800,
|
||||
CPU_FREQ_1000,
|
||||
CPU_FREQ_1200,
|
||||
CPU_FREQ_1400,
|
||||
CPU_FREQ_1600,
|
||||
CPU_FREQ_1700, /* warning: 1700 not recommended by the reference manual
|
||||
we just insert this for performance measurement against
|
||||
Linux, which uses this overclocking */
|
||||
CPU_FREQ_MAX
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* _INCLUDE__PLATFORM__ARNDALE__REGULATOR__CONSTS_H_ */
|
78
os/run/cpufreq.run
Normal file
78
os/run/cpufreq.run
Normal file
@ -0,0 +1,78 @@
|
||||
#
|
||||
# Build
|
||||
#
|
||||
|
||||
# generic components
|
||||
set build_components {
|
||||
core
|
||||
init
|
||||
drivers/platform
|
||||
drivers/timer
|
||||
test/affinity
|
||||
test/cpufreq
|
||||
}
|
||||
|
||||
build $build_components
|
||||
create_boot_directory
|
||||
|
||||
|
||||
#
|
||||
# Config
|
||||
#
|
||||
|
||||
set config {
|
||||
<config>
|
||||
<parent-provides>
|
||||
<service name="ROM"/>
|
||||
<service name="RAM"/>
|
||||
<service name="IRQ"/>
|
||||
<service name="IO_MEM"/>
|
||||
<service name="CAP"/>
|
||||
<service name="PD"/>
|
||||
<service name="RM"/>
|
||||
<service name="CPU"/>
|
||||
<service name="LOG"/>
|
||||
<service name="SIGNAL"/>
|
||||
</parent-provides>
|
||||
<default-route>
|
||||
<any-service> <any-child/> <parent/> </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>
|
||||
</start>
|
||||
<start name="test-affinity">
|
||||
<resource name="RAM" quantum="10M"/>
|
||||
</start>
|
||||
<start name="test-cpufreq">
|
||||
<resource name="RAM" quantum="10M"/>
|
||||
</start>
|
||||
</config>
|
||||
</config>
|
||||
}
|
||||
|
||||
install_config $config
|
||||
|
||||
|
||||
#
|
||||
# Boot modules
|
||||
#
|
||||
|
||||
# generic modules
|
||||
set boot_modules {
|
||||
core
|
||||
init
|
||||
platform_drv
|
||||
timer
|
||||
test-affinity
|
||||
test-cpufreq
|
||||
}
|
||||
|
||||
build_boot_image $boot_modules
|
||||
run_genode_until forever
|
||||
|
244
os/src/drivers/platform/arndale/cmu.h
Normal file
244
os/src/drivers/platform/arndale/cmu.h
Normal file
@ -0,0 +1,244 @@
|
||||
/*
|
||||
* \brief Regulator driver for clock management unit of Exynos5250 SoC
|
||||
* \author Stefan Kalkowski <stefan.kalkowski@genode-labs.com>
|
||||
* \date 2013-06-13
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _CMU_H_
|
||||
#define _CMU_H_
|
||||
|
||||
#include <regulator/consts.h>
|
||||
#include <regulator/driver.h>
|
||||
#include <drivers/board_base.h>
|
||||
#include <os/attached_io_mem_dataspace.h>
|
||||
#include <util/mmio.h>
|
||||
|
||||
using namespace Regulator;
|
||||
|
||||
|
||||
class Cmu : public Regulator::Driver,
|
||||
public Genode::Attached_io_mem_dataspace,
|
||||
public Genode::Mmio
|
||||
{
|
||||
private:
|
||||
|
||||
|
||||
/***********************
|
||||
** CMU CPU registers **
|
||||
***********************/
|
||||
|
||||
struct Apll_lock : Register<0x000, 32>
|
||||
{
|
||||
struct Pll_locktime : Bitfield <0, 20> { };
|
||||
|
||||
static access_t max_lock_time(access_t pdiv) { return pdiv * 250; };
|
||||
};
|
||||
|
||||
struct Apll_con0 : Register<0x100, 32>
|
||||
{
|
||||
struct S : Bitfield <0, 3>
|
||||
{
|
||||
/* S values for frequencies 200 - 1700 */
|
||||
static const Genode::uint8_t values[];
|
||||
};
|
||||
|
||||
struct P : Bitfield <8, 6>
|
||||
{
|
||||
/* P values for frequencies 200 - 1700 */
|
||||
static const Genode::uint8_t values[];
|
||||
};
|
||||
|
||||
struct M : Bitfield <16, 10>
|
||||
{
|
||||
/* M values for frequencies 200 - 1700 */
|
||||
static const Genode::uint16_t values[];
|
||||
};
|
||||
|
||||
struct Locked : Bitfield <29, 1> { };
|
||||
};
|
||||
|
||||
struct Clk_src_cpu : Register<0x200, 32>
|
||||
{
|
||||
struct Mux_cpu_sel : Bitfield<16, 1>
|
||||
{
|
||||
enum { MOUT_APLL, SCLK_MPLL};
|
||||
};
|
||||
};
|
||||
|
||||
struct Clk_mux_stat_cpu : Register<0x400, 32>
|
||||
{
|
||||
struct Cpu_sel : Bitfield<16, 3>
|
||||
{
|
||||
enum { MOUT_APLL = 0b1, SCLK_MPLL = 0b10 };
|
||||
};
|
||||
};
|
||||
|
||||
struct Clk_div_cpu0 : Register<0x500, 32>
|
||||
{
|
||||
/* Cpu0 divider values for frequencies 200 - 1700 */
|
||||
static const Genode::uint32_t values[];
|
||||
};
|
||||
|
||||
struct Clk_div_cpu1 : Register<0x504, 32>
|
||||
{
|
||||
/* Divider for cpu1 doesn't change */
|
||||
enum { FIX_VALUE = 32 };
|
||||
};
|
||||
|
||||
struct Clk_div_stat_cpu0 : Register<0x600, 32>
|
||||
{
|
||||
struct Div_arm : Bitfield< 0, 1> {};
|
||||
struct Div_cpud : Bitfield< 4, 1> {};
|
||||
struct Div_acp : Bitfield< 8, 1> {};
|
||||
struct Div_pheriph : Bitfield<12, 1> {};
|
||||
struct Div_atb : Bitfield<16, 1> {};
|
||||
struct Div_pclk_dbg : Bitfield<20, 1> {};
|
||||
struct Div_apll : Bitfield<24, 1> {};
|
||||
struct Div_arm2 : Bitfield<28, 1> {};
|
||||
|
||||
static bool in_progress(access_t stat_word)
|
||||
{
|
||||
return stat_word & (Div_arm::bits(1) |
|
||||
Div_cpud::bits(1) |
|
||||
Div_acp::bits(1) |
|
||||
Div_pheriph::bits(1) |
|
||||
Div_atb::bits(1) |
|
||||
Div_pclk_dbg::bits(1) |
|
||||
Div_apll::bits(1) |
|
||||
Div_arm2::bits(1));
|
||||
}
|
||||
};
|
||||
|
||||
struct Clk_div_stat_cpu1 : Register<0x604, 32>
|
||||
{
|
||||
struct Div_copy : Bitfield<0, 1> { };
|
||||
struct Div_hpm : Bitfield<4, 1> { };
|
||||
|
||||
static bool in_progress(access_t stat_word)
|
||||
{
|
||||
return stat_word & (Div_copy::bits(1) |
|
||||
Div_hpm::bits(1));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* CPU frequency scaling function
|
||||
*/
|
||||
void _cpu_clk_freq(Cpu_clock_freq freq)
|
||||
{
|
||||
/**
|
||||
* change clock divider values
|
||||
*/
|
||||
|
||||
/* cpu0 divider */
|
||||
write<Clk_div_cpu0>(Clk_div_cpu0::values[freq]);
|
||||
while (Clk_div_stat_cpu0::in_progress(read<Clk_div_stat_cpu0>())) ;
|
||||
|
||||
/* cpu1 divider */
|
||||
write<Clk_div_cpu1>(Clk_div_cpu1::FIX_VALUE);
|
||||
while (Clk_div_stat_cpu1::in_progress(read<Clk_div_stat_cpu1>())) ;
|
||||
|
||||
|
||||
/**
|
||||
* change APLL frequency
|
||||
*/
|
||||
|
||||
/* change reference clock to MPLL */
|
||||
write<Clk_src_cpu::Mux_cpu_sel>(Clk_src_cpu::Mux_cpu_sel::SCLK_MPLL);
|
||||
while (read<Clk_mux_stat_cpu::Cpu_sel>()
|
||||
!= Clk_mux_stat_cpu::Cpu_sel::SCLK_MPLL) ;
|
||||
|
||||
/* set lock time */
|
||||
unsigned pdiv = Apll_con0::P::values[freq];
|
||||
write<Apll_lock::Pll_locktime>(Apll_lock::max_lock_time(pdiv));
|
||||
|
||||
/* change P, M, S values of APLL */
|
||||
write<Apll_con0::P>(Apll_con0::P::values[freq]);
|
||||
write<Apll_con0::M>(Apll_con0::M::values[freq]);
|
||||
write<Apll_con0::S>(Apll_con0::S::values[freq]);
|
||||
|
||||
while (!read<Apll_con0::Locked>()) ;
|
||||
|
||||
/* change reference clock back to APLL */
|
||||
write<Clk_src_cpu::Mux_cpu_sel>(Clk_src_cpu::Mux_cpu_sel::MOUT_APLL);
|
||||
while (read<Clk_mux_stat_cpu::Cpu_sel>()
|
||||
!= Clk_mux_stat_cpu::Cpu_sel::MOUT_APLL) ;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Cmu()
|
||||
: Genode::Attached_io_mem_dataspace(Genode::Board_base::CMU_MMIO_BASE,
|
||||
Genode::Board_base::CMU_MMIO_SIZE),
|
||||
Mmio((Genode::addr_t)local_addr<void>())
|
||||
{
|
||||
/* set CPU to full speed */
|
||||
_cpu_clk_freq(CPU_FREQ_1600);
|
||||
}
|
||||
|
||||
|
||||
/********************************
|
||||
** Regulator driver interface **
|
||||
********************************/
|
||||
|
||||
void set_level(Regulator_id id, unsigned long level)
|
||||
{
|
||||
switch (id) {
|
||||
case CLK_CPU:
|
||||
if (level >= CPU_FREQ_MAX) {
|
||||
PWRN("level=%ld not supported", level);
|
||||
return;
|
||||
}
|
||||
_cpu_clk_freq(static_cast<Cpu_clock_freq>(level));
|
||||
default:
|
||||
PWRN("Unsupported for %s", names[id].name);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long level(Regulator_id id)
|
||||
{
|
||||
switch (id) {
|
||||
default:
|
||||
PWRN("Unsupported for %s", names[id].name);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void set_state(Regulator_id id, bool enable)
|
||||
{
|
||||
switch (id) {
|
||||
default:
|
||||
PWRN("Unsupported for %s", names[id].name);
|
||||
}
|
||||
}
|
||||
|
||||
bool state(Regulator_id id)
|
||||
{
|
||||
switch (id) {
|
||||
default:
|
||||
PWRN("Unsupported for %s", names[id].name);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const Genode::uint8_t Cmu::Apll_con0::S::values[] = { 2, 1, 1, 0, 0, 0, 0, 0, 0 };
|
||||
const Genode::uint16_t Cmu::Apll_con0::M::values[] = { 100, 100, 200, 100, 125,
|
||||
150, 175, 200, 425 };
|
||||
const Genode::uint8_t Cmu::Apll_con0::P::values[] = { 3, 3, 4, 3, 3, 3, 3, 3, 6 };
|
||||
const Genode::uint32_t Cmu::Clk_div_cpu0::values[] = { 0x1117710, 0x1127710, 0x1137710,
|
||||
0x2147710, 0x2147710, 0x3157720,
|
||||
0x4167720, 0x4177730, 0x5377730 };
|
||||
#endif /* _CMU_H_ */
|
55
os/src/drivers/platform/arndale/main.cc
Normal file
55
os/src/drivers/platform/arndale/main.cc
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* \brief Driver for Arndale specific platform devices (clocks, power, etc.)
|
||||
* \author Stefan Kalkowski <stefan.kalkowski@genode-labs.com>
|
||||
* \date 2013-06-13
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#include <base/printf.h>
|
||||
#include <base/sleep.h>
|
||||
#include <cap_session/connection.h>
|
||||
#include <regulator/component.h>
|
||||
#include <regulator/consts.h>
|
||||
|
||||
#include <cmu.h>
|
||||
|
||||
|
||||
struct Driver_factory : Regulator::Driver_factory
|
||||
{
|
||||
Cmu _cmu;
|
||||
|
||||
Regulator::Driver &create(Regulator::Regulator_id id) {
|
||||
switch (id) {
|
||||
case Regulator::CLK_CPU:
|
||||
return _cmu;
|
||||
default:
|
||||
throw Root::Invalid_args(); /* invalid regulator */
|
||||
};
|
||||
}
|
||||
|
||||
void destroy(Regulator::Driver &driver) { }
|
||||
|
||||
};
|
||||
|
||||
|
||||
int main(int, char **)
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
PINF("--- Arndale platform driver ---\n");
|
||||
|
||||
static Cap_connection cap;
|
||||
static Rpc_entrypoint ep(&cap, 4096, "arndale_plat_ep");
|
||||
static ::Driver_factory driver_factory;
|
||||
static Regulator::Root reg_root(&ep, env()->heap(), driver_factory);
|
||||
env()->parent()->announce(ep.manage(®_root));
|
||||
|
||||
sleep_forever();
|
||||
return 0;
|
||||
}
|
5
os/src/drivers/platform/arndale/target.mk
Normal file
5
os/src/drivers/platform/arndale/target.mk
Normal file
@ -0,0 +1,5 @@
|
||||
TARGET = platform_drv
|
||||
REQUIRES = platform_arndale
|
||||
SRC_CC = main.cc
|
||||
INC_DIR += ${PRG_DIR}
|
||||
LIBS = base
|
42
os/src/test/cpufreq/main.cc
Normal file
42
os/src/test/cpufreq/main.cc
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* \brief Test for changing the CPU frequency
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2013-06-14
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/printf.h>
|
||||
#include <base/env.h>
|
||||
#include <base/sleep.h>
|
||||
|
||||
#include <regulator/consts.h>
|
||||
#include <regulator_session/connection.h>
|
||||
#include <timer_session/connection.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
printf("--- test-cpufreq started ---\n");
|
||||
|
||||
static Timer::Connection timer;
|
||||
static Regulator::Connection cpu_regulator(Regulator::CLK_CPU);
|
||||
bool high = true;
|
||||
|
||||
while (true) {
|
||||
timer.msleep(10000);
|
||||
PINF("Setting CPU frequency %s", high ? "low" : "high");
|
||||
cpu_regulator.set_level(high ? Regulator::CPU_FREQ_200
|
||||
: Regulator::CPU_FREQ_1600);
|
||||
high = !high;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
4
os/src/test/cpufreq/target.mk
Normal file
4
os/src/test/cpufreq/target.mk
Normal file
@ -0,0 +1,4 @@
|
||||
TARGET = test-cpufreq
|
||||
REQUIRES = platform_arndale
|
||||
SRC_CC = main.cc
|
||||
LIBS = base
|
Loading…
x
Reference in New Issue
Block a user