Files
genode/repos/os/src/drivers/platform/odroid_x2/cmu.h
Alexy Gallardo Segura c14fe7e6c7 foc: Odroid-X2 basic support
Fix #1597
2015-07-21 09:28:25 +02:00

285 lines
7.2 KiB
C++

/*
* \brief Regulator driver for clock management unit of Exynos4412 SoC
* \author Alexy Gallardo Segura <alexy@uclv.cu>
* \author Humberto Lopez Leon <humberto@uclv.cu>
* \author Reinier Millo Sanchez <rmillo@uclv.cu>
* \date 2015-04-30
*/
/*
* Copyright (C) 2015 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_mmio.h>
#include <base/printf.h>
using namespace Regulator;
class Cmu : public Regulator::Driver,
public Genode::Attached_mmio
{
private:
static const Genode::uint16_t m_values[]; /* M values for frequencies */
static const Genode::uint8_t p_values[]; /* P values for frequencies */
static const Genode::uint8_t s_values[]; /* S values for frequencies */
template <unsigned OFF>
struct Pll_lock : Register<OFF, 32>
{
struct Pll_locktime : Register<OFF, 32>::template Bitfield<0, 20> { };
static Genode::uint32_t max_lock_time(Genode::uint8_t pdiv) {
return pdiv * 250; };
};
template <unsigned OFF>
struct Pll_con0 : Register<OFF, 32>
{
struct S : Register<OFF, 32>::template Bitfield < 0, 3> { };
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> { };
};
/***********************
** CMU CPU registers **
***********************/
typedef Pll_lock<4000> Apll_lock;
typedef Pll_con0<0x4100> Apll_con0;
struct Clk_src_cpu : Register<0x4200, 32>
{
struct Mux_core_sel : Bitfield<16, 1>
{
enum { MOUT_APLL, SCLK_MPLL};
};
};
struct Clk_mux_stat_cpu : Register<0x4400, 32>
{
struct Core_sel : Bitfield<16, 3>
{
enum { MOUT_APLL = 0b1, SCLK_MPLL = 0b10 };
};
};
struct Clk_div_cpu0 : Register<0x4500, 32>
{
/* Cpu0 divider values for frequencies 200 - 1400 */
static const Genode::uint32_t values[];
};
struct Clk_div_cpu1 : Register<0x4504, 32>
{
/* Divider for cpu1 doesn't change */
enum { FIX_VALUE = 32 };
};
struct Clk_div_stat_cpu0 : Register<0x4600, 32>
{
struct Div_core : Bitfield< 0, 1> {};
struct Div_corem0 : Bitfield< 4, 1> {};
struct Div_corem1 : 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_core2 : Bitfield<28, 1> {};
static bool in_progress(access_t stat_word)
{
return stat_word & (Div_core::bits(1) |
Div_corem0::bits(1) |
Div_corem1::bits(1) |
Div_pheriph::bits(1) |
Div_atb::bits(1) |
Div_pclk_dbg::bits(1) |
Div_apll::bits(1) |
Div_core2::bits(1));
}
};
struct Clk_div_stat_cpu1 : Register<0x4604, 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));
}
};
/************************
** CMU CORE registers **
************************/
typedef Pll_lock<0x0008> Mpll_lock;
typedef Pll_con0<0x0108> Mpll_con0;
struct Clk_src_dmc : Register<0x4200, 32>
{
struct Mux_mpll_sel : Bitfield<12, 1> { enum { XXTI, MPLL_FOUT_RGT }; };
};
struct Clk_gate_ip_dmc : Register<0x0900, 32> { };
struct Clk_gate_ip_isp0 : Register<0x8800, 32> { };
struct Clk_gate_ip_isp1 : Register<0x8804, 32> { };
/*******************
** CPU functions **
*******************/
Cpu_clock_freq _cpu_freq;
void _cpu_clk_freq(unsigned long level)
{
PINF("Setting CPU frequency %lu\n",level);
unsigned freq;
switch (level) {
case CPU_FREQ_200:
freq = 0;
break;
case CPU_FREQ_400:
freq = 1;
break;
case CPU_FREQ_600:
freq = 2;
break;
case CPU_FREQ_800:
freq = 3;
break;
case CPU_FREQ_1000:
freq = 4;
break;
case CPU_FREQ_1200:
freq = 5;
break;
case CPU_FREQ_1400:
freq = 6;
break;
default:
PWRN("Unsupported CPU frequency level %ld", level);
PWRN("Supported values are 200, 400, 600, 800, 1000, 1200, 14000 MHz");
PWRN("and 1, 1.2, 1.4, 1.6, 1.7 GHz");
return;
};
/**
* 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_core_sel>(Clk_src_cpu::Mux_core_sel::SCLK_MPLL);
while (read<Clk_mux_stat_cpu::Core_sel>()
!= Clk_mux_stat_cpu::Core_sel::SCLK_MPLL) ;
/* set lock time */
unsigned pdiv = 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>(p_values[freq]);
write<Apll_con0::M>(m_values[freq]);
write<Apll_con0::S>(s_values[freq]);
while (!read<Apll_con0::Locked>()) ;
/* change reference clock back to APLL */
write<Clk_src_cpu::Mux_core_sel>(Clk_src_cpu::Mux_core_sel::MOUT_APLL);
while (read<Clk_mux_stat_cpu::Core_sel>()
!= Clk_mux_stat_cpu::Core_sel::MOUT_APLL) ;
_cpu_freq = static_cast<Cpu_clock_freq>(level);
}
public:
/**
* Constructor
*/
Cmu()
: Genode::Attached_mmio(Genode::Board_base::CMU_MMIO_BASE,
Genode::Board_base::CMU_MMIO_SIZE),
_cpu_freq(CPU_FREQ_1400)
{
/**
* Set default CPU frequency
*/
_cpu_clk_freq(_cpu_freq);
}
/********************************
** Regulator driver interface **
********************************/
void level(Regulator_id id, unsigned long level)
{
switch (id) {
case CLK_CPU:
_cpu_clk_freq(level);
break;
default:
PWRN("Unsupported for %s", names[id].name);
}
}
unsigned long level(Regulator_id id)
{
switch (id) {
case CLK_CPU:
return _cpu_freq;
default:
PWRN("Unsupported for %s", names[id].name);
}
return 0;
}
void state(Regulator_id id, bool enable)
{
}
bool state(Regulator_id id)
{
return true;
}
};
const Genode::uint8_t Cmu::s_values[] = { 2, 1, 1, 0, 0, 0, 0, 0, 0 };
const Genode::uint16_t Cmu::m_values[] = { 100, 100, 200, 100, 125,
150, 175, 200, 425 };
const Genode::uint8_t Cmu::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};
#endif /* _CMU_H_ */